RDPRemoteLoginPro\RDPRemoteLoginPro.csproj
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<TargetFramework>net8.0-windows</TargetFramework>
<OutputType>WinExe</OutputType>
<AssemblyName>MstscOneClick</AssemblyName>
<GenerateAssemblyInfo>false</GenerateAssemblyInfo>
<UseWindowsForms>true</UseWindowsForms>
<ImportWindowsDesktopTargets>true</ImportWindowsDesktopTargets>
</PropertyGroup>
<ItemGroup>
<PackageReference Include="Newtonsoft.Json" Version="13.0.3" />
<PackageReference Include="System.Data.DataSetExtensions" Version="4.5.0" />
<PackageReference Include="System.Configuration.ConfigurationManager" Version="8.0.0" />
</ItemGroup>
</Project>
namespace RDPRemoteLoginPro
{
partial class Form1
{
/// <summary>
/// 必需的设计器变量。
/// </summary>
private System.ComponentModel.IContainer components = null;
/// <summary>
/// 清理所有正在使用的资源。
/// </summary>
/// <param name="disposing">如果应释放托管资源,为 true;否则为 false。</param>
protected override void Dispose(bool disposing)
{
if (disposing && (components != null))
{
components.Dispose();
}
base.Dispose(disposing);
}
#region Windows 窗体设计器生成的代码
/// <summary>
/// 设计器支持所需的方法 - 不要
/// 使用代码编辑器修改此方法的内容。
/// </summary>
private void InitializeComponent()
{
label1 = new System.Windows.Forms.Label();
label2 = new System.Windows.Forms.Label();
UsernameTextBox = new System.Windows.Forms.TextBox();
label3 = new System.Windows.Forms.Label();
PasswordTextBox = new System.Windows.Forms.TextBox();
button1 = new System.Windows.Forms.Button();
AddressComboBox = new System.Windows.Forms.ComboBox();
label4 = new System.Windows.Forms.Label();
NameTextBox = new System.Windows.Forms.TextBox();
SuspendLayout();
//
// label1
//
label1.AutoSize = true;
label1.Location = new System.Drawing.Point(34, 35);
label1.Margin = new System.Windows.Forms.Padding(4, 0, 4, 0);
label1.Name = "label1";
label1.Size = new System.Drawing.Size(56, 20);
label1.TabIndex = 0;
label1.Text = "IP地址:";
label1.TextAlign = System.Drawing.ContentAlignment.MiddleCenter;
label1.Click += label1_Click;
//
// label2
//
label2.AutoSize = true;
label2.Location = new System.Drawing.Point(34, 153);
label2.Margin = new System.Windows.Forms.Padding(4, 0, 4, 0);
label2.Name = "label2";
label2.Size = new System.Drawing.Size(58, 20);
label2.TabIndex = 0;
label2.Text = "用户名:";
label2.TextAlign = System.Drawing.ContentAlignment.MiddleCenter;
//
// UsernameTextBox
//
UsernameTextBox.Location = new System.Drawing.Point(122, 153);
UsernameTextBox.Margin = new System.Windows.Forms.Padding(4, 5, 4, 5);
UsernameTextBox.Name = "UsernameTextBox";
UsernameTextBox.Size = new System.Drawing.Size(223, 27);
UsernameTextBox.TabIndex = 1;
//
// label3
//
label3.AutoSize = true;
label3.Location = new System.Drawing.Point(34, 217);
label3.Margin = new System.Windows.Forms.Padding(4, 0, 4, 0);
label3.Name = "label3";
label3.Size = new System.Drawing.Size(55, 20);
label3.TabIndex = 0;
label3.Text = "密 码:";
label3.TextAlign = System.Drawing.ContentAlignment.MiddleCenter;
//
// PasswordTextBox
//
PasswordTextBox.Location = new System.Drawing.Point(122, 212);
PasswordTextBox.Margin = new System.Windows.Forms.Padding(4, 5, 4, 5);
PasswordTextBox.Name = "PasswordTextBox";
PasswordTextBox.Size = new System.Drawing.Size(223, 27);
PasswordTextBox.TabIndex = 1;
PasswordTextBox.UseSystemPasswordChar = true;
//
// button1
//
button1.Location = new System.Drawing.Point(122, 303);
button1.Margin = new System.Windows.Forms.Padding(4, 5, 4, 5);
button1.Name = "button1";
button1.Size = new System.Drawing.Size(112, 38);
button1.TabIndex = 2;
button1.Text = "连接";
button1.UseVisualStyleBackColor = true;
button1.Click += button1_Click;
//
// AddressComboBox
//
AddressComboBox.FormattingEnabled = true;
AddressComboBox.Location = new System.Drawing.Point(122, 35);
AddressComboBox.Margin = new System.Windows.Forms.Padding(4, 5, 4, 5);
AddressComboBox.Name = "AddressComboBox";
AddressComboBox.Size = new System.Drawing.Size(223, 28);
AddressComboBox.TabIndex = 3;
AddressComboBox.SelectedIndexChanged += AddressComboBox_SelectedIndexChanged;
//
// label4
//
label4.AutoSize = true;
label4.Location = new System.Drawing.Point(34, 92);
label4.Margin = new System.Windows.Forms.Padding(4, 0, 4, 0);
label4.Name = "label4";
label4.Size = new System.Drawing.Size(55, 20);
label4.TabIndex = 0;
label4.Text = "名 称:";
label4.TextAlign = System.Drawing.ContentAlignment.MiddleCenter;
//
// NameTextBox
//
NameTextBox.Location = new System.Drawing.Point(122, 92);
NameTextBox.Margin = new System.Windows.Forms.Padding(4, 5, 4, 5);
NameTextBox.Name = "NameTextBox";
NameTextBox.Size = new System.Drawing.Size(223, 27);
NameTextBox.TabIndex = 1;
//
// Form1
//
AutoScaleDimensions = new System.Drawing.SizeF(9F, 20F);
AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font;
ClientSize = new System.Drawing.Size(384, 380);
Controls.Add(AddressComboBox);
Controls.Add(button1);
Controls.Add(PasswordTextBox);
Controls.Add(label3);
Controls.Add(NameTextBox);
Controls.Add(label4);
Controls.Add(UsernameTextBox);
Controls.Add(label2);
Controls.Add(label1);
FormBorderStyle = System.Windows.Forms.FormBorderStyle.FixedDialog;
Margin = new System.Windows.Forms.Padding(4, 5, 4, 5);
MaximizeBox = false;
MinimizeBox = false;
Name = "Form1";
StartPosition = System.Windows.Forms.FormStartPosition.CenterScreen;
Text = "MSTSC神器";
Load += Form1_Load;
ResumeLayout(false);
PerformLayout();
}
#endregion
private System.Windows.Forms.Label label1;
private System.Windows.Forms.Label label2;
private System.Windows.Forms.TextBox UsernameTextBox;
private System.Windows.Forms.Label label3;
private System.Windows.Forms.TextBox PasswordTextBox;
private System.Windows.Forms.Button button1;
private System.Windows.Forms.ComboBox AddressComboBox;
private System.Windows.Forms.Label label4;
private System.Windows.Forms.TextBox NameTextBox;
}
}
<?xml version="1.0" encoding="utf-8"?>
<root>
<!--
Microsoft ResX Schema
Version 2.0
The primary goals of this format is to allow a simple XML format
that is mostly human readable. The generation and parsing of the
various data types are done through the TypeConverter classes
associated with the data types.
Example:
... ado.net/XML headers & schema ...
<resheader name="resmimetype">text/microsoft-resx</resheader>
<resheader name="version">2.0</resheader>
<resheader name="reader">System.Resources.ResXResourceReader, System.Windows.Forms, ...</resheader>
<resheader name="writer">System.Resources.ResXResourceWriter, System.Windows.Forms, ...</resheader>
<data name="Name1"><value>this is my long string</value><comment>this is a comment</comment></data>
<data name="Color1" type="System.Drawing.Color, System.Drawing">Blue</data>
<data name="Bitmap1" mimetype="application/x-microsoft.net.object.binary.base64">
<value>[base64 mime encoded serialized .NET Framework object]</value>
</data>
<data name="Icon1" type="System.Drawing.Icon, System.Drawing" mimetype="application/x-microsoft.net.object.bytearray.base64">
<value>[base64 mime encoded string representing a byte array form of the .NET Framework object]</value>
<comment>This is a comment</comment>
</data>
There are any number of "resheader" rows that contain simple
name/value pairs.
Each data row contains a name, and value. The row also contains a
type or mimetype. Type corresponds to a .NET class that support
text/value conversion through the TypeConverter architecture.
Classes that don't support this are serialized and stored with the
mimetype set.
The mimetype is used for serialized objects, and tells the
ResXResourceReader how to depersist the object. This is currently not
extensible. For a given mimetype the value must be set accordingly:
Note - application/x-microsoft.net.object.binary.base64 is the format
that the ResXResourceWriter will generate, however the reader can
read any of the formats listed below.
mimetype: application/x-microsoft.net.object.binary.base64
value : The object must be serialized with
: System.Runtime.Serialization.Formatters.Binary.BinaryFormatter
: and then encoded with base64 encoding.
mimetype: application/x-microsoft.net.object.soap.base64
value : The object must be serialized with
: System.Runtime.Serialization.Formatters.Soap.SoapFormatter
: and then encoded with base64 encoding.
mimetype: application/x-microsoft.net.object.bytearray.base64
value : The object must be serialized into a byte array
: using a System.ComponentModel.TypeConverter
: and then encoded with base64 encoding.
-->
<xsd:schema id="root" xmlns="" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:msdata="urn:schemas-microsoft-com:xml-msdata">
<xsd:import namespace="http://www.w3.org/XML/1998/namespace" />
<xsd:element name="root" msdata:IsDataSet="true">
<xsd:complexType>
<xsd:choice maxOccurs="unbounded">
<xsd:element name="metadata">
<xsd:complexType>
<xsd:sequence>
<xsd:element name="value" type="xsd:string" minOccurs="0" />
</xsd:sequence>
<xsd:attribute name="name" use="required" type="xsd:string" />
<xsd:attribute name="type" type="xsd:string" />
<xsd:attribute name="mimetype" type="xsd:string" />
<xsd:attribute ref="xml:space" />
</xsd:complexType>
</xsd:element>
<xsd:element name="assembly">
<xsd:complexType>
<xsd:attribute name="alias" type="xsd:string" />
<xsd:attribute name="name" type="xsd:string" />
</xsd:complexType>
</xsd:element>
<xsd:element name="data">
<xsd:complexType>
<xsd:sequence>
<xsd:element name="value" type="xsd:string" minOccurs="0" msdata:Ordinal="1" />
<xsd:element name="comment" type="xsd:string" minOccurs="0" msdata:Ordinal="2" />
</xsd:sequence>
<xsd:attribute name="name" type="xsd:string" use="required" msdata:Ordinal="1" />
<xsd:attribute name="type" type="xsd:string" msdata:Ordinal="3" />
<xsd:attribute name="mimetype" type="xsd:string" msdata:Ordinal="4" />
<xsd:attribute ref="xml:space" />
</xsd:complexType>
</xsd:element>
<xsd:element name="resheader">
<xsd:complexType>
<xsd:sequence>
<xsd:element name="value" type="xsd:string" minOccurs="0" msdata:Ordinal="1" />
</xsd:sequence>
<xsd:attribute name="name" type="xsd:string" use="required" />
</xsd:complexType>
</xsd:element>
</xsd:choice>
</xsd:complexType>
</xsd:element>
</xsd:schema>
<resheader name="resmimetype">
<value>text/microsoft-resx</value>
</resheader>
<resheader name="version">
<value>2.0</value>
</resheader>
<resheader name="reader">
<value>System.Resources.ResXResourceReader, System.Windows.Forms, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
</resheader>
<resheader name="writer">
<value>System.Resources.ResXResourceWriter, System.Windows.Forms, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
</resheader>
</root>
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Diagnostics;
using System.Drawing;
using System.IO;
using System.Linq;
using System.Text;
using System.Windows.Forms;
using RDPRemoteLoginPro;
namespace RDPRemoteLoginPro
{
public partial class Form1 : Form
{
private string _filename;
private string _address;
private string _linkName;
private string _username;
private string _password;
public Form1()
{
InitializeComponent();
}
private void button1_Click(object sender, EventArgs e)
{
Connect();
SaveConfig();
}
/// <summary>
/// 执行命令行命令
/// </summary>
/// <param name="cmd"></param>
/// <returns></returns>
void ProcCmd(String cmd)
{
Process p = new Process();
p.StartInfo.FileName = "cmd.exe";
p.StartInfo.UseShellExecute = false;
p.StartInfo.RedirectStandardInput = true;
p.StartInfo.RedirectStandardOutput = true;
p.StartInfo.RedirectStandardError = true;
p.StartInfo.CreateNoWindow = true;
p.Start();
p.StandardInput.WriteLine(cmd);
p.StandardInput.WriteLine("exit");
}
private void Form1_Load(object sender, EventArgs e)
{
AddressComboBox.Select();
LoadConfig();
}
private void LoadConfig()
{
List<Server> servers = ConfigHelper.GetServers();
if (servers.Count == 0)
{
AddressComboBox.Text = "请输入IP地址";
UsernameTextBox.PlaceholderText = "计算机名称";
PasswordTextBox.PlaceholderText = "用户名";
NameTextBox.PlaceholderText = "请输入密码";
}
else
{
List<string> serverIps = servers.Select(x => x.ServerIp).ToList();
foreach (string ip in serverIps)
{
AddressComboBox.Items.Add(ip);
}
AddressComboBox.SelectedIndex = 0;
UsernameTextBox.Text = servers.First().User;
PasswordTextBox.Text = servers.First().Password;
NameTextBox.Text = servers.First().LinkName;
}
}
private void SaveConfig()
{
ConfigHelper.AddAndUpdateServer(
new Server
{
ServerIp = AddressComboBox.Text,
LinkName = NameTextBox.Text,
User = UsernameTextBox.Text,
Password = PasswordTextBox.Text,
});
}
private void Connect()
{
if (
string.IsNullOrEmpty(AddressComboBox.Text)
|| string.IsNullOrEmpty(UsernameTextBox.Text)
|| string.IsNullOrEmpty(PasswordTextBox.Text)
|| string.IsNullOrEmpty(NameTextBox.Text.Trim())
)
{
MessageBox.Show(@"请检查配置!");
return;
}
var TemplateStr = RDPRemoteLoginPro.Properties.Resources.TemplateRDP; //获取RDP模板字符串
//用DataProtection加密密码,并转化成二进制字符串
var pwstr = BitConverter.ToString(
DataProtection.ProtectData(Encoding.Unicode.GetBytes(PasswordTextBox.Text), "")
);
pwstr = pwstr.Replace("-", "");
//替换模板里面的关键字符串,生成当前的drp字符串
var NewStr = TemplateStr
.Replace("{#address}", AddressComboBox.Text)
.Replace("{#username}", UsernameTextBox.Text)
.Replace("{#password}", pwstr);
//将drp保存到文件,并放在程序目录下,等待使用
_filename = NameTextBox.Text + "0" + ".rdp";
StreamWriter sw = new StreamWriter(_filename);
sw.Write(NewStr);
sw.Close();
//利用CMD命令调用MSTSC
ProcCmd("mstsc -admin " + _filename);
this.ShowInTaskbar = true;
this.WindowState = FormWindowState.Minimized; //使当前窗体最小化
}
private void AddressComboBox_SelectedIndexChanged(object sender, EventArgs e)
{
// 获取 ComboBox 实例
ComboBox comboBox = sender as ComboBox;
if (comboBox != null)
{
// 或者获取选中项的实际值(通常与数据源的绑定相关)
string serverIp = (string)comboBox.SelectedItem;
var server = ConfigHelper.GetServerByIp(serverIp.Trim());
NameTextBox.Text = server.LinkName;
UsernameTextBox.Text = server.User;
PasswordTextBox.Text = server.Password;
}
}
private void label1_Click(object sender, EventArgs e)
{
}
}
}
RDPRemoteLoginPro\ConfigHelper.cs
using Newtonsoft.Json;
using System;
using System.Collections.Generic;
using System.Configuration;
using System.IO;
using System.Linq;
using System.Text.RegularExpressions;
using System.Xml;
using System.Xml.Linq;
namespace RDPRemoteLoginPro
{
public static class ConfigHelper
{
static string _configPath = @"serverData.json";
static List<Server> _servers = new List<Server>();
static ConfigHelper()
{
if (!File.Exists(_configPath))
{
string jsonString = JsonConvert.SerializeObject(_servers);
File.WriteAllText(_configPath, jsonString);
}
}
public static List<Server> GetServers()
{
string jsonContent = File.ReadAllText(_configPath);
// 将json字符串转换为Server对象
List<Server> serversInfos =
JsonConvert.DeserializeObject<List<Server>>(jsonContent)
?? throw new Exception("server is null");
_servers.AddRange(serversInfos);
return _servers;
}
public static Server GetServerByIp(string ip)
{
if (_servers.Count == 0)
{
string jsonContent = File.ReadAllText(_configPath);
// 将json字符串转换为Server对象
List<Server> serversInfos =
JsonConvert.DeserializeObject<List<Server>>(jsonContent)
?? throw new Exception("server is null");
_servers.AddRange(serversInfos);
}
Server server = _servers.Where(x => x.ServerIp == ip).First();
return server;
}
public static void AddAndUpdateServer(Server server)
{
if (_servers.Count == 0)
{
// 读取json文件内容
string jsonContent = File.ReadAllText(_configPath);
// 将json字符串转换为Server对象
List<Server> serversInfos =
JsonConvert.DeserializeObject<List<Server>>(jsonContent)
?? throw new Exception("server is null");
_servers.AddRange(serversInfos);
}
bool isExist = _servers.Exists(x => x.ServerIp == server.ServerIp);
if (isExist)
{
Server server1 = _servers.Where(x => x.ServerIp == server.ServerIp).First();
server1.LinkName = server.LinkName;
server1.User = server.User;
server1.Password = server.Password;
}
else
{
_servers.Add(server);
}
string jsonString = JsonConvert.SerializeObject(_servers);
File.WriteAllText(_configPath, jsonString);
}
}
}
RDPRemoteLoginPro\DataProtection.cs
using System;
using System.Runtime.InteropServices;
using System.Text;
using System.Security;
namespace RDPRemoteLoginPro
{
[Serializable()]
public sealed class DataProtection
{
[Flags()]
public enum CryptProtectPromptFlags
{
CRYPTPROTECT_PROMPT_ON_UNPROTECT = 0x01,
CRYPTPROTECT_PROMPT_ON_PROTECT = 0x02,
CRYPTPROTECT_PROMPT_RESERVED = 0x04,
CRYPTPROTECT_PROMPT_STRONG = 0x08,
CRYPTPROTECT_PROMPT_REQUIRE_STRONG = 0x10
}
[Flags()]
public enum CryptProtectDataFlags
{
CRYPTPROTECT_UI_FORBIDDEN = 0x01,
CRYPTPROTECT_LOCAL_MACHINE = 0x04,
CRYPTPROTECT_CRED_SYNC = 0x08,
CRYPTPROTECT_AUDIT = 0x10,
CRYPTPROTECT_NO_RECOVERY = 0x20,
CRYPTPROTECT_VERIFY_PROTECTION = 0x40,
CRYPTPROTECT_CRED_REGENERATE = 0x80
}
#region 加密数据
public static string ProtectData(string data, string name)
{
return ProtectData(data, name,
CryptProtectDataFlags.CRYPTPROTECT_UI_FORBIDDEN | CryptProtectDataFlags.CRYPTPROTECT_LOCAL_MACHINE);
}
public static byte[] ProtectData(byte[] data, string name)
{
return ProtectData(data, name,
CryptProtectDataFlags.CRYPTPROTECT_UI_FORBIDDEN | CryptProtectDataFlags.CRYPTPROTECT_LOCAL_MACHINE);
}
public static string ProtectData(string data, string name, CryptProtectDataFlags flags)
{
byte[] dataIn = Encoding.Unicode.GetBytes(data);
byte[] dataOut = ProtectData(dataIn, name, flags);
if (dataOut != null)
return (Convert.ToBase64String(dataOut));
else
return null;
}
/// <summary>
/// 加密数据
/// </summary>
/// <param name="data">要加密的明文数据</param>
/// <param name="name">有意义的描述,此描述会加到加密后的数据中</param>
/// <param name="dwFlags">flags的位标志</param>
/// <returns></returns>
private static byte[] ProtectData(byte[] data, string name, CryptProtectDataFlags dwFlags)
{
byte[] cipherText = null;
// copy data into unmanaged memory
//DATA_BLOB结构,用于CryptProtectData参数
DPAPI.DATA_BLOB din = new DPAPI.DATA_BLOB();
din.cbData = data.Length;
//Marshal类的作用:提供了一个方法集,这些方法用于分配非托管内存、复制非托管内存块、将托管类型转换为非托管类型,
//此外还提供了在与非托管代码交互时使用的其他杂项方法。
//为din.pbData分配内存
din.pbData = Marshal.AllocHGlobal(din.cbData);
//InPtr结构:用于表示指针或句柄的平台特定类型
//分配内存错误,抛出内存不足异常
//IntPtr.Zero:一个只读字段,代表已初始化为零的指针或句柄
if (din.pbData.Equals(IntPtr.Zero))
throw new OutOfMemoryException("Unable to allocate memory for buffer.");
//将data数组中的数据复制到pbData内存指针中
Marshal.Copy(data, 0, din.pbData, din.cbData);
//声明DPAPI类的DATA_BLOB公共结构类型
DPAPI.DATA_BLOB dout = new DPAPI.DATA_BLOB();
try
{
//加密数据
bool cryptoRetval = DPAPI.CryptProtectData(ref din, name, IntPtr.Zero, IntPtr.Zero, IntPtr.Zero, dwFlags, ref dout);
//判断加密是否成功
if (cryptoRetval) // 成功
{
int startIndex = 0;
//分配cipherText数据元素大小为dout.cbData
cipherText = new byte[dout.cbData];
//从dout.pbData内存指针指向的内容拷贝到byte数组cipherText中
Marshal.Copy(dout.pbData, cipherText, startIndex, dout.cbData);
//从内存中释放指针指向的数据I
DPAPI.LocalFree(dout.pbData);
}
else
{
//加密失败,获得错误信息
int errCode = Marshal.GetLastWin32Error();
StringBuilder buffer = new StringBuilder(256);
//显示错误信息
Win32Error.FormatMessage(Win32Error.FormatMessageFlags.FORMAT_MESSAGE_FROM_SYSTEM, IntPtr.Zero, errCode, 0, buffer, buffer.Capacity, IntPtr.Zero);
}
}
finally
{
// 如果din.pbData非空,则释放din.pbData使用的内存
if (!din.pbData.Equals(IntPtr.Zero))
Marshal.FreeHGlobal(din.pbData);
}
//返回加密后的数据
return cipherText;
}
#endregion
//解密数据
internal static void InitPromptstruct(ref DPAPI.CRYPTPROTECT_PROMPTSTRUCT ps)
{
ps.cbSize = Marshal.SizeOf(typeof(DPAPI.CRYPTPROTECT_PROMPTSTRUCT));
ps.dwPromptFlags = 0;
ps.hwndApp = IntPtr.Zero;
ps.szPrompt = null;
}
}
//允许托管代码不经过堆栈步即调入非托管代码
[SuppressUnmanagedCodeSecurityAttribute()]
internal class DPAPI
{
[DllImport("crypt32")]
public static extern bool CryptProtectData(ref DATA_BLOB dataIn, string szDataDescr, IntPtr optionalEntropy, IntPtr pvReserved,
IntPtr pPromptStruct, DataProtection.CryptProtectDataFlags dwFlags, ref DATA_BLOB pDataOut);
[DllImport("crypt32")]
public static extern bool CryptUnprotectData(ref DATA_BLOB dataIn, StringBuilder ppszDataDescr, IntPtr optionalEntropy,
IntPtr pvReserved, IntPtr pPromptStruct, DataProtection.CryptProtectDataFlags dwFlags, ref DATA_BLOB pDataOut);
[DllImport("Kernel32.dll")]
public static extern IntPtr LocalFree(IntPtr hMem);
[StructLayout(LayoutKind.Sequential)]
public struct DATA_BLOB
{
public int cbData;
public IntPtr pbData;
}
[StructLayout(LayoutKind.Sequential)]
public struct CRYPTPROTECT_PROMPTSTRUCT
{
public int cbSize; // = Marshal.SizeOf(typeof(CRYPTPROTECT_PROMPTSTRUCT))
public int dwPromptFlags; // = 0
public IntPtr hwndApp; // = IntPtr.Zero
public string szPrompt; // = null
}
}
internal class Win32Error
{
[Flags()]
public enum FormatMessageFlags : int
{
FORMAT_MESSAGE_ALLOCATE_BUFFER = 0x0100,
FORMAT_MESSAGE_IGNORE_INSERTS = 0x0200,
FORMAT_MESSAGE_FROM_STRING = 0x0400,
FORMAT_MESSAGE_FROM_HMODULE = 0x0800,
FORMAT_MESSAGE_FROM_SYSTEM = 0x1000,
FORMAT_MESSAGE_ARGUMENT_ARRAY = 0x2000,
FORMAT_MESSAGE_MAX_WIDTH_MASK = 0xFF,
}
[DllImport("Kernel32.dll")]
public static extern int FormatMessage(FormatMessageFlags flags, IntPtr source, int messageId, int languageId,
StringBuilder buffer, int size, IntPtr arguments);
}
}
RDPRemoteLoginPro\Server.cs
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace RDPRemoteLoginPro
{
public class Server
{
public string ServerIp { get; set; }
public string LinkName { get; set; }
public string User { get; set; }
public string Password { get; set; }
}
}
RDPRemoteLoginPro\RDPRemoteLoginPro.csproj.user
<?xml version="1.0" encoding="utf-8"?>
<Project ToolsVersion="Current" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<PropertyGroup />
<ItemGroup>
<Compile Update="Form1.cs">
<SubType>Form</SubType>
</Compile>
</ItemGroup>
</Project>
RDPRemoteLoginPro\RDPRemoteLoginPro.sln
Microsoft Visual Studio Solution File, Format Version 12.00
# Visual Studio 15
VisualStudioVersion = 15.0.28010.2048
MinimumVisualStudioVersion = 10.0.40219.1
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "RDPRemoteLoginPro", "RDPRemoteLoginPro.csproj", "{F14DB645-6273-48E7-8CBD-E823A27BD9DC}"
EndProject
Global
GlobalSection(SolutionConfigurationPlatforms) = preSolution
Debug|Any CPU = Debug|Any CPU
Release|Any CPU = Release|Any CPU
EndGlobalSection
GlobalSection(ProjectConfigurationPlatforms) = postSolution
{F14DB645-6273-48E7-8CBD-E823A27BD9DC}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{F14DB645-6273-48E7-8CBD-E823A27BD9DC}.Debug|Any CPU.Build.0 = Debug|Any CPU
{F14DB645-6273-48E7-8CBD-E823A27BD9DC}.Release|Any CPU.ActiveCfg = Release|Any CPU
{F14DB645-6273-48E7-8CBD-E823A27BD9DC}.Release|Any CPU.Build.0 = Release|Any CPU
EndGlobalSection
GlobalSection(SolutionProperties) = preSolution
HideSolutionNode = FALSE
EndGlobalSection
GlobalSection(ExtensibilityGlobals) = postSolution
SolutionGuid = {66A1728E-08D1-488F-864D-EDCD804E34F1}
EndGlobalSection
EndGlobal
RDPRemoteLoginPro\Program.cs
using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.Linq;
using System.Reflection;
using System.Runtime.InteropServices;
using System.Windows.Forms;
using RDPRemoteLoginPro;
namespace RDPRemoteLoginPro
{
static class Program
{
/// <summary>
/// window form show count
/// </summary>
private const int WS_SHOWNORMAL = 1;
[DllImport("User32.dll")]
private static extern bool ShowWindowAsync(IntPtr hWnd, int cmdShow);
[DllImport("User32.dll")]
private static extern bool SetForegroundWindow(IntPtr hWnd);
[DllImport("kernel32.dll")]
private static extern IntPtr LoadLibrary(string sLibName);
/// <summary>
/// 应用程序的主入口点。
/// </summary>
[STAThread]
static void Main()
{
//Application.EnableVisualStyles();
//Application.SetCompatibleTextRenderingDefault(false);
//Application.Run(new Form1());
Process instance = RunningInstance();
if (instance == null)
{
Application.EnableVisualStyles();
Application.SetCompatibleTextRenderingDefault(false);
Application.Run(new Form1());
}
else
{
HandleRunningInstance(instance);
}
}
/// <summary>
/// application repeat start
/// </summary>
public static void ApplicationRepeatStart()
{
Process instance = RunningInstance();
if (instance != null)
{
HandleRunningInstance(instance);
}
}
/// <summary>
/// Running process instance
/// </summary>
/// <returns>the running process</returns>
public static Process RunningInstance()
{
Process current = Process.GetCurrentProcess();
Process[] processes = Process.GetProcessesByName(current.ProcessName);
////Loop through the running processes in with the same name
foreach (Process process in processes)
{
////Ignore the current process
if (process.Id != current.Id)
{
////Make sure that the process is running from the exe file.
if (Assembly.GetExecutingAssembly().Location.Replace("/", "\\") == current.MainModule.FileName)
{
////Return the other process instance.
return process;
}
}
}
////No other instance was found, return null.
return null;
}
/// <summary>
/// handle running instance
/// </summary>
/// <param name="instance">the running process</param>
public static void HandleRunningInstance(Process instance)
{
////Make sure the window is not minimized or maximized
ShowWindowAsync(instance.MainWindowHandle, WS_SHOWNORMAL);
////Set the real instance to foreground window
SetForegroundWindow(instance.MainWindowHandle);
}
}
}
RDPRemoteLoginPro\Resources\TemplateRDP.txt
screen mode id:i:2
use multimon:i:0
desktopwidth:i:1600
desktopheight:i:900
session bpp:i:32
winposstr:s:0,3,0,0,800,600
compression:i:1
keyboardhook:i:2
audiocapturemode:i:0
videoplaybackmode:i:1
connection type:i:2
networkautodetect:i:1
bandwidthautodetect:i:1
displayconnectionbar:i:1
enableworkspacereconnect:i:0
disable wallpaper:i:1
allow font smoothing:i:0
allow desktop composition:i:0
disable full window drag:i:1
disable menu anims:i:1
disable themes:i:0
disable cursor setting:i:0
bitmapcachepersistenable:i:1
audiomode:i:1
redirectprinters:i:1
redirectcomports:i:0
redirectsmartcards:i:1
redirectclipboard:i:1
redirectposdevices:i:0
autoreconnection enabled:i:1
authentication level:i:2
prompt for credentials:i:0
negotiate security layer:i:1
remoteapplicationmode:i:0
alternate shell:s:
shell working directory:s:
gatewayhostname:s:
gatewayusagemethod:i:4
gatewaycredentialssource:i:4
gatewayprofileusagemethod:i:0
promptcredentialonce:i:0
use redirection server name:i:0
rdgiskdcproxy:i:0
kdcproxyname:s:
drivestoredirect:s:
redirectdirectx:i:1
full address:s:{#address}
username:s:{#username}
password 51:b:{#password}