From 20bce4eb6184dbe81a7a94b3d21597f54f0c8b2f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E6=96=87=E7=8E=8B=E7=8E=8B?= <596461462@qq.com> Date: Wed, 4 Dec 2019 11:09:00 +0800 Subject: [PATCH 01/19] =?UTF-8?q?=C3=86=C3=81=C4=BB=C3=8A=C3=93=CD=BC?= =?UTF-8?q?=C3=82=D6=B2=C2=A5(=CE=B4=C3=8D=C3=AA=C2=B3=C3=89?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit )s --- SiMay.Core/Packets/DesktopViewGetFramePack.cs | 7 ++ .../MainService/MainService.cs | 7 +- SiMay.RemoteClient.NewCore/Program.cs | 2 +- .../Properties/app.manifest | 2 +- .../SiMay.ServiceCore.csproj | 3 + SiMay.RemoteClient.NewCore/app.manifest | 69 +++++++++++++ SiMay.RemoteControlsCore/AppConfiguration.cs | 23 ++++- .../AppMainAdapterHandler.cs | 26 ++--- .../Interface/IDesktopView.cs | 6 ++ .../DesktopViewWallSettingForm.Designer.cs | 0 .../DesktopViewWallSettingForm.cs | 0 .../DesktopViewWallSettingForm.resx | 0 .../ViewCarouselContext.cs | 42 ++++++++ .../MainApplication.Designer.cs | 99 ++++++++++--------- .../MainApplication/MainApplication.cs | 71 ++++++++++++- .../SiMay.RemoteMonitor.csproj | 7 +- .../UserControls/UDesktopView.cs | 1 + .../UserControls/UToolStripMenuItem.cs | 4 +- 18 files changed, 296 insertions(+), 73 deletions(-) create mode 100644 SiMay.RemoteClient.NewCore/app.manifest rename SiMay.RemoteMonitor/MainApplication/{DesktopView => DesktopViewCarousel}/DesktopViewWallSettingForm.Designer.cs (100%) rename SiMay.RemoteMonitor/MainApplication/{DesktopView => DesktopViewCarousel}/DesktopViewWallSettingForm.cs (100%) rename SiMay.RemoteMonitor/MainApplication/{DesktopView => DesktopViewCarousel}/DesktopViewWallSettingForm.resx (100%) create mode 100644 SiMay.RemoteMonitor/MainApplication/DesktopViewCarousel/ViewCarouselContext.cs diff --git a/SiMay.Core/Packets/DesktopViewGetFramePack.cs b/SiMay.Core/Packets/DesktopViewGetFramePack.cs index f42c4b8..2bca51e 100644 --- a/SiMay.Core/Packets/DesktopViewGetFramePack.cs +++ b/SiMay.Core/Packets/DesktopViewGetFramePack.cs @@ -10,5 +10,12 @@ namespace SiMay.Core.Packets public int Height { get; set; } public int Width { get; set; } public int TimeSpan { get; set; } + public bool InVisbleArea { get; set; } + } + + public class DesktopViewFramePack : BasePacket + { + public bool InVisbleArea { get; set; } + public byte[] ViewData { get; set; } } } diff --git a/SiMay.RemoteClient.NewCore/MainService/MainService.cs b/SiMay.RemoteClient.NewCore/MainService/MainService.cs index d0bb626..40c53c5 100644 --- a/SiMay.RemoteClient.NewCore/MainService/MainService.cs +++ b/SiMay.RemoteClient.NewCore/MainService/MainService.cs @@ -509,8 +509,11 @@ namespace SiMay.ServiceCore.MainService Thread.Sleep(getframe.TimeSpan); - byte[] data = MessageHelper.CopyMessageHeadTo(MessageHead.C_MAIN_SCREENWALL_IMG, - ImageExtensionHelper.CaptureNoCursorToBytes(new Size(getframe.Width, getframe.Height))); + byte[] data = MessageHelper.CopyMessageHeadTo(MessageHead.C_MAIN_SCREENWALL_IMG, new DesktopViewFramePack() + { + InVisbleArea = getframe.InVisbleArea, + ViewData = getframe.InVisbleArea ? ImageExtensionHelper.CaptureNoCursorToBytes(new Size(getframe.Width, getframe.Height)) : new byte[0] + }); SendMessageToServer(data); }); diff --git a/SiMay.RemoteClient.NewCore/Program.cs b/SiMay.RemoteClient.NewCore/Program.cs index 1ed977f..f07236a 100644 --- a/SiMay.RemoteClient.NewCore/Program.cs +++ b/SiMay.RemoteClient.NewCore/Program.cs @@ -85,7 +85,7 @@ namespace SiMay.ServiceCore UniqueId = "AAAAAAAAAAAAAAA11111111", ServiceName = "SiMayService", ServiceDisplayName = "SiMay远程被控服务", - InstallService = true + InstallService = false }; try { diff --git a/SiMay.RemoteClient.NewCore/Properties/app.manifest b/SiMay.RemoteClient.NewCore/Properties/app.manifest index b84d395..31caee1 100644 --- a/SiMay.RemoteClient.NewCore/Properties/app.manifest +++ b/SiMay.RemoteClient.NewCore/Properties/app.manifest @@ -18,8 +18,8 @@ + - diff --git a/SiMay.RemoteClient.NewCore/SiMay.ServiceCore.csproj b/SiMay.RemoteClient.NewCore/SiMay.ServiceCore.csproj index 6da54e2..f4a5ef8 100644 --- a/SiMay.RemoteClient.NewCore/SiMay.ServiceCore.csproj +++ b/SiMay.RemoteClient.NewCore/SiMay.ServiceCore.csproj @@ -87,6 +87,9 @@ + + Properties\app.manifest + ..\AForge.dll\AForge.Video.dll diff --git a/SiMay.RemoteClient.NewCore/app.manifest b/SiMay.RemoteClient.NewCore/app.manifest new file mode 100644 index 0000000..8c579dc --- /dev/null +++ b/SiMay.RemoteClient.NewCore/app.manifest @@ -0,0 +1,69 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/SiMay.RemoteControlsCore/AppConfiguration.cs b/SiMay.RemoteControlsCore/AppConfiguration.cs index a0ac09f..c744a63 100644 --- a/SiMay.RemoteControlsCore/AppConfiguration.cs +++ b/SiMay.RemoteControlsCore/AppConfiguration.cs @@ -30,7 +30,10 @@ namespace SiMay.RemoteControlsCore { "SessionMode", "0" }, { "AccessKey", "522222" }, { "ServiceIPAddress", "127.0.0.1" }, - { "ServicePort", "522" } + { "ServicePort", "522" }, + { "EnabledCarousel", "false" }, + { "CarouselInterval", "5000" }, + { "CarouselViewCount", "6"} }; string _filePath = Path.Combine(Environment.CurrentDirectory, "SiMayConfig.ini"); @@ -171,5 +174,23 @@ namespace SiMay.RemoteControlsCore get { return SysConfig.GetConfig("ServicePort"); } set { SysConfig.SetConfig("ServicePort", value); } } + + public static bool EnabledCarousel + { + get { return bool.Parse(SysConfig.GetConfig("EnabledCarousel")); } + set { SysConfig.SetConfig("EnabledCarousel", value.ToString()); } + } + + public static int CarouselInterval + { + get { return int.Parse(SysConfig.GetConfig("CarouselInterval")); } + set { SysConfig.SetConfig("CarouselInterval", value.ToString()); } + } + + public static int CarouselViewCount + { + get { return int.Parse(SysConfig.GetConfig("CarouselViewCount")); } + set { SysConfig.SetConfig("CarouselViewCount", value.ToString()); } + } } } \ No newline at end of file diff --git a/SiMay.RemoteControlsCore/AppMainAdapterHandler.cs b/SiMay.RemoteControlsCore/AppMainAdapterHandler.cs index cb1b6d3..7acd4ae 100644 --- a/SiMay.RemoteControlsCore/AppMainAdapterHandler.cs +++ b/SiMay.RemoteControlsCore/AppMainAdapterHandler.cs @@ -399,15 +399,7 @@ namespace SiMay.RemoteControlsCore return; view.Caption = describePack.MachineName + "-(" + describePack.RemarkInformation + ")"; syncContext.KeyDictions[SysConstants.DesktopView] = view; - - byte[] data = MessageHelper.CopyMessageHeadTo( - MessageHead.S_MAIN_SCREENWALL_GETIMG, new DesktopViewGetFramePack() - { - Height = view.Height, - Width = view.Width, - TimeSpan = this.ViewRefreshInterval - }); - session.SendAsync(data); + this.GetViewFrame(session, view); } @@ -423,17 +415,25 @@ namespace SiMay.RemoteControlsCore syncContext.KeyDictions[SysConstants.DesktopView] == null) return; + var frameData = session.CompletedBuffer.GetMessageEntity(); var view = syncContext.KeyDictions[SysConstants.DesktopView].ConvertTo(); + if (frameData.InVisbleArea) + { + using (var ms = new MemoryStream(frameData.ViewData)) + view.PlayerDekstopView(Image.FromStream(ms)); + } + this.GetViewFrame(session, view); + } - using (var ms = new MemoryStream(session.CompletedBuffer.GetMessagePayload())) - view.PlayerDekstopView(Image.FromStream(ms)); - + private void GetViewFrame(SessionHandler session, IDesktopView view) + { byte[] data = MessageHelper.CopyMessageHeadTo( MessageHead.S_MAIN_SCREENWALL_GETIMG, new DesktopViewGetFramePack() { Height = view.Height, Width = view.Width, - TimeSpan = this.ViewRefreshInterval + TimeSpan = this.ViewRefreshInterval, + InVisbleArea = view.InVisbleArea }); session.SendAsync(data); diff --git a/SiMay.RemoteControlsCore/Interface/IDesktopView.cs b/SiMay.RemoteControlsCore/Interface/IDesktopView.cs index 0b3a90d..cf19285 100644 --- a/SiMay.RemoteControlsCore/Interface/IDesktopView.cs +++ b/SiMay.RemoteControlsCore/Interface/IDesktopView.cs @@ -21,6 +21,12 @@ namespace SiMay.RemoteControlsCore /// 视图标题 /// string Caption { get; set; } + + /// + /// 是否在可播放区域 + /// + bool InVisbleArea { get; set; } + /// /// 会话同步上下文 /// diff --git a/SiMay.RemoteMonitor/MainApplication/DesktopView/DesktopViewWallSettingForm.Designer.cs b/SiMay.RemoteMonitor/MainApplication/DesktopViewCarousel/DesktopViewWallSettingForm.Designer.cs similarity index 100% rename from SiMay.RemoteMonitor/MainApplication/DesktopView/DesktopViewWallSettingForm.Designer.cs rename to SiMay.RemoteMonitor/MainApplication/DesktopViewCarousel/DesktopViewWallSettingForm.Designer.cs diff --git a/SiMay.RemoteMonitor/MainApplication/DesktopView/DesktopViewWallSettingForm.cs b/SiMay.RemoteMonitor/MainApplication/DesktopViewCarousel/DesktopViewWallSettingForm.cs similarity index 100% rename from SiMay.RemoteMonitor/MainApplication/DesktopView/DesktopViewWallSettingForm.cs rename to SiMay.RemoteMonitor/MainApplication/DesktopViewCarousel/DesktopViewWallSettingForm.cs diff --git a/SiMay.RemoteMonitor/MainApplication/DesktopView/DesktopViewWallSettingForm.resx b/SiMay.RemoteMonitor/MainApplication/DesktopViewCarousel/DesktopViewWallSettingForm.resx similarity index 100% rename from SiMay.RemoteMonitor/MainApplication/DesktopView/DesktopViewWallSettingForm.resx rename to SiMay.RemoteMonitor/MainApplication/DesktopViewCarousel/DesktopViewWallSettingForm.resx diff --git a/SiMay.RemoteMonitor/MainApplication/DesktopViewCarousel/ViewCarouselContext.cs b/SiMay.RemoteMonitor/MainApplication/DesktopViewCarousel/ViewCarouselContext.cs new file mode 100644 index 0000000..34b124c --- /dev/null +++ b/SiMay.RemoteMonitor/MainApplication/DesktopViewCarousel/ViewCarouselContext.cs @@ -0,0 +1,42 @@ +using SiMay.RemoteControlsCore; +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace SiMay.RemoteMonitor.MainApplication +{ + public class ViewCarouselContext + { + /// + /// 轮播间隔 + /// + public int ViewCarouselInterval { get; set; } + + /// + /// 视图行 + /// + public int ViewRow { get; set; } + + /// + /// 视图列 + /// + public int ViewColum { get; set; } + + /// + /// 停留视图 + /// + public IList AlwaysViews { get; set; } + + /// + /// 是否启用轮播 + /// + public bool Enabled { get; set; } + + public ViewCarouselContext() + { + AlwaysViews = new List(); + } + } +} diff --git a/SiMay.RemoteMonitor/MainApplication/MainApplication.Designer.cs b/SiMay.RemoteMonitor/MainApplication/MainApplication.Designer.cs index 2bb4d98..2a78426 100644 --- a/SiMay.RemoteMonitor/MainApplication/MainApplication.Designer.cs +++ b/SiMay.RemoteMonitor/MainApplication/MainApplication.Designer.cs @@ -65,6 +65,7 @@ this.splitContainer1 = new System.Windows.Forms.SplitContainer(); this.desktopViewLayout = new System.Windows.Forms.FlowLayoutPanel(); this.panel1 = new System.Windows.Forms.Panel(); + this.linkLabel2 = new System.Windows.Forms.LinkLabel(); this.label3 = new System.Windows.Forms.Label(); this.groupBox = new System.Windows.Forms.ComboBox(); this.label2 = new System.Windows.Forms.Label(); @@ -81,10 +82,8 @@ this.splitContainer2 = new System.Windows.Forms.SplitContainer(); this.tabControl2 = new System.Windows.Forms.TabControl(); this.tabPage2 = new System.Windows.Forms.TabPage(); - this.logList = new SiMay.RemoteMonitor.UserControls.UListView(); this.tabControl1 = new System.Windows.Forms.TabControl(); this.tabPage1 = new System.Windows.Forms.TabPage(); - this.onlineList = new SiMay.RemoteMonitor.UserControls.UListView(); this.statusStrip1 = new System.Windows.Forms.StatusStrip(); this.toolStripStatusLabel1 = new System.Windows.Forms.ToolStripStatusLabel(); this.stripHost = new System.Windows.Forms.ToolStripStatusLabel(); @@ -118,7 +117,8 @@ this.桌面记录查看ToolStripMenuItem = new System.Windows.Forms.ToolStripMenuItem(); this.锁定ToolStripMenuItem = new System.Windows.Forms.ToolStripMenuItem(); this.toolStripMenuItem3 = new System.Windows.Forms.ToolStripMenuItem(); - this.linkLabel2 = new System.Windows.Forms.LinkLabel(); + this.logList = new SiMay.RemoteMonitor.UserControls.UListView(); + this.onlineList = new SiMay.RemoteMonitor.UserControls.UListView(); this.CmdContext.SuspendLayout(); this.logsContext.SuspendLayout(); ((System.ComponentModel.ISupportInitialize)(this.splitContainer1)).BeginInit(); @@ -422,10 +422,11 @@ this.desktopViewLayout.BorderStyle = System.Windows.Forms.BorderStyle.FixedSingle; this.desktopViewLayout.Dock = System.Windows.Forms.DockStyle.Fill; this.desktopViewLayout.Location = new System.Drawing.Point(0, 0); - this.desktopViewLayout.Margin = new System.Windows.Forms.Padding(4); + this.desktopViewLayout.Margin = new System.Windows.Forms.Padding(0); this.desktopViewLayout.Name = "desktopViewLayout"; this.desktopViewLayout.Size = new System.Drawing.Size(1476, 567); this.desktopViewLayout.TabIndex = 3; + this.desktopViewLayout.Resize += new System.EventHandler(this.desktopViewLayout_Resize); // // panel1 // @@ -450,6 +451,18 @@ this.panel1.Size = new System.Drawing.Size(1476, 30); this.panel1.TabIndex = 4; // + // linkLabel2 + // + this.linkLabel2.Anchor = ((System.Windows.Forms.AnchorStyles)((System.Windows.Forms.AnchorStyles.Bottom | System.Windows.Forms.AnchorStyles.Right))); + this.linkLabel2.AutoSize = true; + this.linkLabel2.Location = new System.Drawing.Point(1396, 8); + this.linkLabel2.Margin = new System.Windows.Forms.Padding(4, 0, 4, 0); + this.linkLabel2.Name = "linkLabel2"; + this.linkLabel2.Size = new System.Drawing.Size(67, 15); + this.linkLabel2.TabIndex = 13; + this.linkLabel2.TabStop = true; + this.linkLabel2.Text = "视图设置"; + // // label3 // this.label3.Anchor = ((System.Windows.Forms.AnchorStyles)((System.Windows.Forms.AnchorStyles.Bottom | System.Windows.Forms.AnchorStyles.Right))); @@ -671,23 +684,6 @@ this.tabPage2.Text = "运行日志"; this.tabPage2.UseVisualStyleBackColor = true; // - // logList - // - this.logList.BorderStyle = System.Windows.Forms.BorderStyle.None; - this.logList.ContextMenuStrip = this.logsContext; - this.logList.Dock = System.Windows.Forms.DockStyle.Fill; - this.logList.FullRowSelect = true; - this.logList.HideSelection = false; - this.logList.Location = new System.Drawing.Point(4, 4); - this.logList.Margin = new System.Windows.Forms.Padding(4); - this.logList.Name = "logList"; - this.logList.Size = new System.Drawing.Size(352, 190); - this.logList.TabIndex = 0; - this.logList.UseCompatibleStateImageBehavior = false; - this.logList.UseWindowsThemStyle = true; - this.logList.View = System.Windows.Forms.View.Details; - this.logList.MouseEnter += new System.EventHandler(this.logList_MouseEnter); - // // tabControl1 // this.tabControl1.Alignment = System.Windows.Forms.TabAlignment.Bottom; @@ -713,24 +709,6 @@ this.tabPage1.Text = "在线列表"; this.tabPage1.UseVisualStyleBackColor = true; // - // onlineList - // - this.onlineList.BorderStyle = System.Windows.Forms.BorderStyle.None; - this.onlineList.CheckBoxes = true; - this.onlineList.ContextMenuStrip = this.CmdContext; - this.onlineList.Dock = System.Windows.Forms.DockStyle.Fill; - this.onlineList.FullRowSelect = true; - this.onlineList.HideSelection = false; - this.onlineList.Location = new System.Drawing.Point(4, 4); - this.onlineList.Margin = new System.Windows.Forms.Padding(4); - this.onlineList.Name = "onlineList"; - this.onlineList.Size = new System.Drawing.Size(1091, 190); - this.onlineList.TabIndex = 0; - this.onlineList.UseCompatibleStateImageBehavior = false; - this.onlineList.UseWindowsThemStyle = false; - this.onlineList.View = System.Windows.Forms.View.Details; - this.onlineList.MouseEnter += new System.EventHandler(this.onlineList_MouseEnter); - // // statusStrip1 // this.statusStrip1.ImageScalingSize = new System.Drawing.Size(20, 20); @@ -1032,17 +1010,40 @@ this.toolStripMenuItem3.Text = "关于程序(&H)"; this.toolStripMenuItem3.Click += new System.EventHandler(this.About); // - // linkLabel2 + // logList // - this.linkLabel2.Anchor = ((System.Windows.Forms.AnchorStyles)((System.Windows.Forms.AnchorStyles.Bottom | System.Windows.Forms.AnchorStyles.Right))); - this.linkLabel2.AutoSize = true; - this.linkLabel2.Location = new System.Drawing.Point(1396, 8); - this.linkLabel2.Margin = new System.Windows.Forms.Padding(4, 0, 4, 0); - this.linkLabel2.Name = "linkLabel2"; - this.linkLabel2.Size = new System.Drawing.Size(67, 15); - this.linkLabel2.TabIndex = 13; - this.linkLabel2.TabStop = true; - this.linkLabel2.Text = "视图设置"; + this.logList.BorderStyle = System.Windows.Forms.BorderStyle.None; + this.logList.ContextMenuStrip = this.logsContext; + this.logList.Dock = System.Windows.Forms.DockStyle.Fill; + this.logList.FullRowSelect = true; + this.logList.HideSelection = false; + this.logList.Location = new System.Drawing.Point(4, 4); + this.logList.Margin = new System.Windows.Forms.Padding(4); + this.logList.Name = "logList"; + this.logList.Size = new System.Drawing.Size(352, 190); + this.logList.TabIndex = 0; + this.logList.UseCompatibleStateImageBehavior = false; + this.logList.UseWindowsThemStyle = true; + this.logList.View = System.Windows.Forms.View.Details; + this.logList.MouseEnter += new System.EventHandler(this.logList_MouseEnter); + // + // onlineList + // + this.onlineList.BorderStyle = System.Windows.Forms.BorderStyle.None; + this.onlineList.CheckBoxes = true; + this.onlineList.ContextMenuStrip = this.CmdContext; + this.onlineList.Dock = System.Windows.Forms.DockStyle.Fill; + this.onlineList.FullRowSelect = true; + this.onlineList.HideSelection = false; + this.onlineList.Location = new System.Drawing.Point(4, 4); + this.onlineList.Margin = new System.Windows.Forms.Padding(4); + this.onlineList.Name = "onlineList"; + this.onlineList.Size = new System.Drawing.Size(1091, 190); + this.onlineList.TabIndex = 0; + this.onlineList.UseCompatibleStateImageBehavior = false; + this.onlineList.UseWindowsThemStyle = false; + this.onlineList.View = System.Windows.Forms.View.Details; + this.onlineList.MouseEnter += new System.EventHandler(this.onlineList_MouseEnter); // // MainApplication // diff --git a/SiMay.RemoteMonitor/MainApplication/MainApplication.cs b/SiMay.RemoteMonitor/MainApplication/MainApplication.cs index fb9385e..faa9923 100644 --- a/SiMay.RemoteMonitor/MainApplication/MainApplication.cs +++ b/SiMay.RemoteMonitor/MainApplication/MainApplication.cs @@ -40,6 +40,8 @@ namespace SiMay.RemoteMonitor.MainApplication private const string GROUP_ALL = "全部"; private System.Timers.Timer _timer; + private System.Timers.Timer _viewCarouselTimer; + private ViewCarouselContext _viewCarouselContext = new ViewCarouselContext(); private Color _closeScreenColor = Color.FromArgb(127, 175, 219); private ImageList _imgList; @@ -168,7 +170,72 @@ namespace SiMay.RemoteMonitor.MainApplication if (isLock) //锁住主控界面 LockWindow(); } + + _viewCarouselTimer = new System.Timers.Timer(AppConfiguration.CarouselInterval); + _viewCarouselTimer.Elapsed += ViewCarouselFunc; + + //if (AppConfiguration.EnabledCarousel) + _viewCarouselTimer.Start(); + + _viewCarouselContext.ViewRow = 3; + _viewCarouselContext.ViewColum = 3; + } + private void desktopViewLayout_Resize(object sender, EventArgs e) + { + ViewOnResize(); + } + private void ViewOnResize() + { + if (this.desktopViewLayout.Controls.Count <= 0) + return; + + var viewCount = _viewCarouselContext.ViewColum * _viewCarouselContext.ViewRow; + + var marginalRight = 25 / this._viewCarouselContext.ViewColum; + var width = (this.desktopViewLayout.ClientRectangle.Width / _viewCarouselContext.ViewColum) - marginalRight; + var height = (this.desktopViewLayout.ClientRectangle.Height / _viewCarouselContext.ViewRow) - marginalRight; + + int index = 0; + foreach (IDesktopView view in this.desktopViewLayout.Controls) + { + var containerRectangle = this.desktopViewLayout.ClientRectangle; + + if (view is Control control) + { + var controlRectangle = control.DisplayRectangle; + if (containerRectangle) + { + + } + } + if (view.Width == width && view.Height == height && index++ == viewCount) + continue; + + this.InvokeUI(() => + { + view.Height = height; + view.Width = width; + }); + } } + private void ViewCarouselFunc(object sender, System.Timers.ElapsedEventArgs e) + { + var viewCount = _viewCarouselContext.ViewColum * _viewCarouselContext.ViewRow; + if (this.desktopViewLayout.Controls.Count > viewCount) + { + this.InvokeUI(() => + { + var view = this.desktopViewLayout.Controls[this.desktopViewLayout.Controls.Count - 1].ConvertTo(); + if (!_viewCarouselContext.AlwaysViews.Contains(view)) + this.desktopViewLayout.Controls.SetChildIndex(view as Control, _viewCarouselContext.AlwaysViews.Count); + }); + } + + this.ViewOnResize(); + } + + private void InvokeUI(Action action) => this.Invoke(new Action(action)); + /// /// 初始化通信库 /// @@ -363,7 +430,7 @@ namespace SiMay.RemoteMonitor.MainApplication private void StripMenu_Click(object sender, EventArgs e) { var ustripbtn = sender as UToolStripMenuItem; - string appkey = ustripbtn.CtrlType.GetAppKey(); + string appkey = ustripbtn.ApplicationType.GetAppKey(); this.GetSelectedListItem().ForEach(c => { this._appMainAdapterHandler.RemoteActiveService(c.SessionSyncContext, appkey); @@ -900,5 +967,7 @@ namespace SiMay.RemoteMonitor.MainApplication this._appMainAdapterHandler.RemoteSetSessionState(c.SessionSyncContext, SystemSessionType.UnInstallService); }); } + + } } \ No newline at end of file diff --git a/SiMay.RemoteMonitor/SiMay.RemoteMonitor.csproj b/SiMay.RemoteMonitor/SiMay.RemoteMonitor.csproj index 5b8ef1f..6870e3f 100644 --- a/SiMay.RemoteMonitor/SiMay.RemoteMonitor.csproj +++ b/SiMay.RemoteMonitor/SiMay.RemoteMonitor.csproj @@ -158,12 +158,13 @@ - + Form - + DesktopViewWallSettingForm.cs + Form @@ -383,7 +384,7 @@ DesktopRecordViewerForm.cs - + DesktopViewWallSettingForm.cs diff --git a/SiMay.RemoteMonitor/UserControls/UDesktopView.cs b/SiMay.RemoteMonitor/UserControls/UDesktopView.cs index 183092e..f973caf 100644 --- a/SiMay.RemoteMonitor/UserControls/UDesktopView.cs +++ b/SiMay.RemoteMonitor/UserControls/UDesktopView.cs @@ -33,6 +33,7 @@ namespace SiMay.RemoteMonitor.UserControls } public SessionSyncContext SessionSyncContext { get; set; } + public bool InVisbleArea { get; set; } private void img_DoubleClick(object sender, EventArgs e) { diff --git a/SiMay.RemoteMonitor/UserControls/UToolStripMenuItem.cs b/SiMay.RemoteMonitor/UserControls/UToolStripMenuItem.cs index b7d821f..9fb09c9 100644 --- a/SiMay.RemoteMonitor/UserControls/UToolStripMenuItem.cs +++ b/SiMay.RemoteMonitor/UserControls/UToolStripMenuItem.cs @@ -10,8 +10,8 @@ namespace SiMay.RemoteMonitor.UserControls { public UToolStripMenuItem(string name, Type type) : base(name) - => CtrlType = type; + => ApplicationType = type; - public Type CtrlType { get; set; } + public Type ApplicationType { get; set; } } } -- Gitee From 8dac772f258de1e07bb2b95b4dec9cfb934b5801 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E6=96=87=E7=8E=8B=E7=8E=8B?= <596461462@qq.com> Date: Thu, 5 Dec 2019 00:42:28 +0800 Subject: [PATCH 02/19] =?UTF-8?q?=E5=B1=8F=E5=B9=95=E8=A7=86=E5=9B=BE?= =?UTF-8?q?=E8=BD=AE=E6=92=AD(=E6=9C=AA=E6=B5=8B=E8=AF=95)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- SiMay.RemoteClient.NewCore/Program.cs | 2 +- SiMay.RemoteControlsCore/AppConfiguration.cs | 42 ++-- ...ontext.cs => DesktopViewSettingContext.cs} | 67 +++++- .../DesktopViewWallSettingForm.Designer.cs | 147 +++++++++++- .../DesktopViewWallSettingForm.cs | 41 +++- .../MainApplication.Designer.cs | 221 +++++++----------- .../MainApplication/MainApplication.cs | 103 ++++---- .../SiMay.RemoteMonitor.csproj | 2 +- 8 files changed, 396 insertions(+), 229 deletions(-) rename SiMay.RemoteMonitor/MainApplication/DesktopViewCarousel/{ViewCarouselContext.cs => DesktopViewSettingContext.cs} (32%) diff --git a/SiMay.RemoteClient.NewCore/Program.cs b/SiMay.RemoteClient.NewCore/Program.cs index f07236a..5b2c0e8 100644 --- a/SiMay.RemoteClient.NewCore/Program.cs +++ b/SiMay.RemoteClient.NewCore/Program.cs @@ -69,7 +69,7 @@ namespace SiMay.ServiceCore { var startParameter = new StartParameterEx() { - Host = "192.168.1.105", + Host = "127.0.0.1", Port = 5200, //Port = 522, GroupName = "默认分组", diff --git a/SiMay.RemoteControlsCore/AppConfiguration.cs b/SiMay.RemoteControlsCore/AppConfiguration.cs index c744a63..2d4da05 100644 --- a/SiMay.RemoteControlsCore/AppConfiguration.cs +++ b/SiMay.RemoteControlsCore/AppConfiguration.cs @@ -17,13 +17,11 @@ namespace SiMay.RemoteControlsCore { "ConnectPassWord", "5200" }, { "MaxConnectCount", "100000" }, { "Maximize", "false" }, - { "DesktopViewHeight", "220" }, - { "DesktopViewWidth", "280" }, { "lHosts", "127.0.0.1:5200" }, { "DbClickViewExc", "" }, { "LockPassWord", "5200" }, { "WindowsIsLock", "false" }, - { "DesktopRefreshTimeSpan", "1500" }, + { "DesktopRefreshInterval", "1500" }, { "AudioSamplesPerSecond", "8000" }, { "AudioBitsPerSample", "16" }, { "AudioChannels", "1" }, @@ -31,9 +29,10 @@ namespace SiMay.RemoteControlsCore { "AccessKey", "522222" }, { "ServiceIPAddress", "127.0.0.1" }, { "ServicePort", "522" }, - { "EnabledCarousel", "false" }, + { "EnabledCarousel", "true" }, { "CarouselInterval", "5000" }, - { "CarouselViewCount", "6"} + { "ViewColumn", "4" }, + { "ViewRow", "3" }, }; string _filePath = Path.Combine(Environment.CurrentDirectory, "SiMayConfig.ini"); @@ -91,19 +90,6 @@ namespace SiMay.RemoteControlsCore get { return SysConfig.GetConfig("Maximize"); } set { SysConfig.SetConfig("Maximize", value); } } - - public static string DesktopViewHeight - { - get { return SysConfig.GetConfig("DesktopViewHeight"); } - set { SysConfig.SetConfig("DesktopViewHeight", value); } - } - - public static string DesktopViewWidth - { - get { return SysConfig.GetConfig("DesktopViewWidth"); } - set { SysConfig.SetConfig("DesktopViewWidth", value); } - } - public static string LHostString { get { return SysConfig.GetConfig("lHosts"); } @@ -128,10 +114,10 @@ namespace SiMay.RemoteControlsCore set { SysConfig.SetConfig("WindowsIsLock", value); } } - public static string DesktopRefreshTimeSpan + public static int DesktopRefreshInterval { - get { return SysConfig.GetConfig("DesktopRefreshTimeSpan"); } - set { SysConfig.SetConfig("DesktopRefreshTimeSpan", value); } + get { return int.Parse(SysConfig.GetConfig("DesktopRefreshInterval")); } + set { SysConfig.SetConfig("DesktopRefreshInterval", value.ToString()); } } public static string AudioSamplesPerSecond @@ -175,7 +161,7 @@ namespace SiMay.RemoteControlsCore set { SysConfig.SetConfig("ServicePort", value); } } - public static bool EnabledCarousel + public static bool CarouselEnabled { get { return bool.Parse(SysConfig.GetConfig("EnabledCarousel")); } set { SysConfig.SetConfig("EnabledCarousel", value.ToString()); } @@ -187,10 +173,16 @@ namespace SiMay.RemoteControlsCore set { SysConfig.SetConfig("CarouselInterval", value.ToString()); } } - public static int CarouselViewCount + public static int ViewColumn + { + get { return int.Parse(SysConfig.GetConfig("ViewColumn")); } + set { SysConfig.SetConfig("ViewColumn", value.ToString()); } + } + + public static int ViewRow { - get { return int.Parse(SysConfig.GetConfig("CarouselViewCount")); } - set { SysConfig.SetConfig("CarouselViewCount", value.ToString()); } + get { return int.Parse(SysConfig.GetConfig("ViewRow")); } + set { SysConfig.SetConfig("ViewRow", value.ToString()); } } } } \ No newline at end of file diff --git a/SiMay.RemoteMonitor/MainApplication/DesktopViewCarousel/ViewCarouselContext.cs b/SiMay.RemoteMonitor/MainApplication/DesktopViewCarousel/DesktopViewSettingContext.cs similarity index 32% rename from SiMay.RemoteMonitor/MainApplication/DesktopViewCarousel/ViewCarouselContext.cs rename to SiMay.RemoteMonitor/MainApplication/DesktopViewCarousel/DesktopViewSettingContext.cs index 34b124c..db69902 100644 --- a/SiMay.RemoteMonitor/MainApplication/DesktopViewCarousel/ViewCarouselContext.cs +++ b/SiMay.RemoteMonitor/MainApplication/DesktopViewCarousel/DesktopViewSettingContext.cs @@ -7,22 +7,67 @@ using System.Threading.Tasks; namespace SiMay.RemoteMonitor.MainApplication { - public class ViewCarouselContext + public class DesktopViewSettingContext { /// /// 轮播间隔 /// - public int ViewCarouselInterval { get; set; } + public int ViewCarouselInterval + { + get + { + return AppConfiguration.CarouselInterval; + } + set + { + AppConfiguration.CarouselInterval = value; + } + } + + /// + /// 视图刷新间隔 + /// + public int ViewFreshInterval + { + get + { + return AppConfiguration.DesktopRefreshInterval; + } + set + { + AppConfiguration.DesktopRefreshInterval = value; + } + } /// /// 视图行 /// - public int ViewRow { get; set; } + public int ViewRow + { + get + { + return AppConfiguration.ViewRow; + } + set + { + AppConfiguration.ViewRow = value; + } + } /// /// 视图列 /// - public int ViewColum { get; set; } + public int ViewColum + { + get + { + return AppConfiguration.ViewColumn; + } + set + { + AppConfiguration.ViewColumn = value; + } + } /// /// 停留视图 @@ -32,9 +77,19 @@ namespace SiMay.RemoteMonitor.MainApplication /// /// 是否启用轮播 /// - public bool Enabled { get; set; } + public bool CarouselEnabled + { + get + { + return AppConfiguration.CarouselEnabled; + } + set + { + AppConfiguration.CarouselEnabled = value; + } + } - public ViewCarouselContext() + public DesktopViewSettingContext() { AlwaysViews = new List(); } diff --git a/SiMay.RemoteMonitor/MainApplication/DesktopViewCarousel/DesktopViewWallSettingForm.Designer.cs b/SiMay.RemoteMonitor/MainApplication/DesktopViewCarousel/DesktopViewWallSettingForm.Designer.cs index d190fe0..00fb508 100644 --- a/SiMay.RemoteMonitor/MainApplication/DesktopViewCarousel/DesktopViewWallSettingForm.Designer.cs +++ b/SiMay.RemoteMonitor/MainApplication/DesktopViewCarousel/DesktopViewWallSettingForm.Designer.cs @@ -28,21 +28,166 @@ /// private void InitializeComponent() { + this.label2 = new System.Windows.Forms.Label(); + this.deskrefreshTimeInterval = new System.Windows.Forms.NumericUpDown(); + this.label1 = new System.Windows.Forms.Label(); + this.enabled = new System.Windows.Forms.CheckBox(); + this.button1 = new System.Windows.Forms.Button(); + this.label3 = new System.Windows.Forms.Label(); + this.carouselInterval = new System.Windows.Forms.NumericUpDown(); + ((System.ComponentModel.ISupportInitialize)(this.deskrefreshTimeInterval)).BeginInit(); + ((System.ComponentModel.ISupportInitialize)(this.carouselInterval)).BeginInit(); this.SuspendLayout(); // + // label2 + // + this.label2.Anchor = ((System.Windows.Forms.AnchorStyles)((System.Windows.Forms.AnchorStyles.Bottom | System.Windows.Forms.AnchorStyles.Right))); + this.label2.AutoSize = true; + this.label2.Location = new System.Drawing.Point(76, 49); + this.label2.Margin = new System.Windows.Forms.Padding(4, 0, 4, 0); + this.label2.Name = "label2"; + this.label2.Size = new System.Drawing.Size(75, 15); + this.label2.TabIndex = 12; + this.label2.Text = "刷新间隔:"; + // + // deskrefreshTimeInterval + // + this.deskrefreshTimeInterval.Anchor = ((System.Windows.Forms.AnchorStyles)((System.Windows.Forms.AnchorStyles.Bottom | System.Windows.Forms.AnchorStyles.Right))); + this.deskrefreshTimeInterval.Increment = new decimal(new int[] { + 100, + 0, + 0, + 0}); + this.deskrefreshTimeInterval.Location = new System.Drawing.Point(156, 43); + this.deskrefreshTimeInterval.Margin = new System.Windows.Forms.Padding(4); + this.deskrefreshTimeInterval.Maximum = new decimal(new int[] { + 10000, + 0, + 0, + 0}); + this.deskrefreshTimeInterval.Minimum = new decimal(new int[] { + 300, + 0, + 0, + 0}); + this.deskrefreshTimeInterval.Name = "deskrefreshTimeInterval"; + this.deskrefreshTimeInterval.ReadOnly = true; + this.deskrefreshTimeInterval.Size = new System.Drawing.Size(123, 25); + this.deskrefreshTimeInterval.TabIndex = 11; + this.deskrefreshTimeInterval.TextAlign = System.Windows.Forms.HorizontalAlignment.Center; + this.deskrefreshTimeInterval.Value = new decimal(new int[] { + 300, + 0, + 0, + 0}); + // + // label1 + // + this.label1.Anchor = ((System.Windows.Forms.AnchorStyles)((System.Windows.Forms.AnchorStyles.Bottom | System.Windows.Forms.AnchorStyles.Right))); + this.label1.AutoSize = true; + this.label1.Location = new System.Drawing.Point(76, 111); + this.label1.Margin = new System.Windows.Forms.Padding(4, 0, 4, 0); + this.label1.Name = "label1"; + this.label1.Size = new System.Drawing.Size(75, 15); + this.label1.TabIndex = 13; + this.label1.Text = "启用轮播:"; + // + // enabled + // + this.enabled.AutoSize = true; + this.enabled.Location = new System.Drawing.Point(157, 110); + this.enabled.Name = "enabled"; + this.enabled.Size = new System.Drawing.Size(59, 19); + this.enabled.TabIndex = 14; + this.enabled.Text = "启用"; + this.enabled.UseVisualStyleBackColor = true; + this.enabled.CheckedChanged += new System.EventHandler(this.checkBox1_CheckedChanged); + // + // button1 + // + this.button1.Location = new System.Drawing.Point(394, 145); + this.button1.Name = "button1"; + this.button1.Size = new System.Drawing.Size(109, 41); + this.button1.TabIndex = 15; + this.button1.Text = "保存"; + this.button1.UseVisualStyleBackColor = true; + this.button1.Click += new System.EventHandler(this.button1_Click); + // + // label3 + // + this.label3.Anchor = ((System.Windows.Forms.AnchorStyles)((System.Windows.Forms.AnchorStyles.Bottom | System.Windows.Forms.AnchorStyles.Right))); + this.label3.AutoSize = true; + this.label3.Location = new System.Drawing.Point(76, 82); + this.label3.Margin = new System.Windows.Forms.Padding(4, 0, 4, 0); + this.label3.Name = "label3"; + this.label3.Size = new System.Drawing.Size(75, 15); + this.label3.TabIndex = 17; + this.label3.Text = "轮播间隔:"; + // + // carouselInterval + // + this.carouselInterval.Anchor = ((System.Windows.Forms.AnchorStyles)((System.Windows.Forms.AnchorStyles.Bottom | System.Windows.Forms.AnchorStyles.Right))); + this.carouselInterval.Increment = new decimal(new int[] { + 100, + 0, + 0, + 0}); + this.carouselInterval.Location = new System.Drawing.Point(156, 76); + this.carouselInterval.Margin = new System.Windows.Forms.Padding(4); + this.carouselInterval.Maximum = new decimal(new int[] { + 10000, + 0, + 0, + 0}); + this.carouselInterval.Minimum = new decimal(new int[] { + 300, + 0, + 0, + 0}); + this.carouselInterval.Name = "carouselInterval"; + this.carouselInterval.ReadOnly = true; + this.carouselInterval.Size = new System.Drawing.Size(123, 25); + this.carouselInterval.TabIndex = 16; + this.carouselInterval.TextAlign = System.Windows.Forms.HorizontalAlignment.Center; + this.carouselInterval.Value = new decimal(new int[] { + 300, + 0, + 0, + 0}); + // // DesktopViewWallSettingForm // this.AutoScaleDimensions = new System.Drawing.SizeF(8F, 15F); this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font; - this.ClientSize = new System.Drawing.Size(558, 322); + this.ClientSize = new System.Drawing.Size(524, 198); + this.Controls.Add(this.label3); + this.Controls.Add(this.carouselInterval); + this.Controls.Add(this.button1); + this.Controls.Add(this.enabled); + this.Controls.Add(this.label1); + this.Controls.Add(this.label2); + this.Controls.Add(this.deskrefreshTimeInterval); this.FormBorderStyle = System.Windows.Forms.FormBorderStyle.FixedSingle; this.MaximizeBox = false; this.Name = "DesktopViewWallSettingForm"; + this.StartPosition = System.Windows.Forms.FormStartPosition.CenterScreen; this.Text = "视图墙设置"; + this.Load += new System.EventHandler(this.DesktopViewWallSettingForm_Load); + ((System.ComponentModel.ISupportInitialize)(this.deskrefreshTimeInterval)).EndInit(); + ((System.ComponentModel.ISupportInitialize)(this.carouselInterval)).EndInit(); this.ResumeLayout(false); + this.PerformLayout(); } #endregion + + private System.Windows.Forms.Label label2; + private System.Windows.Forms.NumericUpDown deskrefreshTimeInterval; + private System.Windows.Forms.Label label1; + private System.Windows.Forms.CheckBox enabled; + private System.Windows.Forms.Button button1; + private System.Windows.Forms.Label label3; + private System.Windows.Forms.NumericUpDown carouselInterval; } } \ No newline at end of file diff --git a/SiMay.RemoteMonitor/MainApplication/DesktopViewCarousel/DesktopViewWallSettingForm.cs b/SiMay.RemoteMonitor/MainApplication/DesktopViewCarousel/DesktopViewWallSettingForm.cs index 3b39d78..c66930d 100644 --- a/SiMay.RemoteMonitor/MainApplication/DesktopViewCarousel/DesktopViewWallSettingForm.cs +++ b/SiMay.RemoteMonitor/MainApplication/DesktopViewCarousel/DesktopViewWallSettingForm.cs @@ -7,14 +7,53 @@ using System.Linq; using System.Text; using System.Threading.Tasks; using System.Windows.Forms; +using SiMay.Basic; namespace SiMay.RemoteMonitor.MainApplication { public partial class DesktopViewWallSettingForm : Form { - public DesktopViewWallSettingForm() + DesktopViewSettingContext _settingContext; + public DesktopViewWallSettingForm(DesktopViewSettingContext settingContext) { + _settingContext = settingContext; InitializeComponent(); } + + private void button1_Click(object sender, EventArgs e) + { + if (deskrefreshTimeInterval.Value < 300) + { + MessageBoxHelper.ShowBoxError("设置未保存,刷新间隔不能小于300!", "error"); + return; + } + this._settingContext.ViewFreshInterval = (int)deskrefreshTimeInterval.Value; + this._settingContext.CarouselEnabled = this.enabled.Checked; + this._settingContext.ViewCarouselInterval = (int)carouselInterval.Value; + this.DialogResult = DialogResult.OK; + this.Close(); + } + + private void checkBox1_CheckedChanged(object sender, EventArgs e) + { + this.SwithTip(); + } + + private void SwithTip() + { + if (enabled.Checked) + enabled.Text = "启用"; + else + enabled.Text = "不启用"; + } + + private void DesktopViewWallSettingForm_Load(object sender, EventArgs e) + { + this.DialogResult = DialogResult.Cancel; + this.deskrefreshTimeInterval.Value = this._settingContext.ViewFreshInterval; + this.carouselInterval.Value = this._settingContext.ViewCarouselInterval; + this.enabled.Checked = this._settingContext.CarouselEnabled; + this.SwithTip(); + } } } diff --git a/SiMay.RemoteMonitor/MainApplication/MainApplication.Designer.cs b/SiMay.RemoteMonitor/MainApplication/MainApplication.Designer.cs index 2a78426..fb4ae7f 100644 --- a/SiMay.RemoteMonitor/MainApplication/MainApplication.Designer.cs +++ b/SiMay.RemoteMonitor/MainApplication/MainApplication.Designer.cs @@ -68,22 +68,22 @@ this.linkLabel2 = new System.Windows.Forms.LinkLabel(); this.label3 = new System.Windows.Forms.Label(); this.groupBox = new System.Windows.Forms.ComboBox(); - this.label2 = new System.Windows.Forms.Label(); - this.deskrefreshTimeSpan = new System.Windows.Forms.NumericUpDown(); this.button2 = new System.Windows.Forms.Button(); this.button1 = new System.Windows.Forms.Button(); this.column = new System.Windows.Forms.Label(); this.fsd = new System.Windows.Forms.Label(); this.row = new System.Windows.Forms.Label(); - this.rowtrackBar = new System.Windows.Forms.TrackBar(); + this.columntrackBar = new System.Windows.Forms.TrackBar(); this.linkLabel1 = new System.Windows.Forms.LinkLabel(); this.label1 = new System.Windows.Forms.Label(); - this.columntrackBar = new System.Windows.Forms.TrackBar(); + this.rowtrackBar = new System.Windows.Forms.TrackBar(); this.splitContainer2 = new System.Windows.Forms.SplitContainer(); this.tabControl2 = new System.Windows.Forms.TabControl(); this.tabPage2 = new System.Windows.Forms.TabPage(); + this.logList = new SiMay.RemoteMonitor.UserControls.UListView(); this.tabControl1 = new System.Windows.Forms.TabControl(); this.tabPage1 = new System.Windows.Forms.TabPage(); + this.onlineList = new SiMay.RemoteMonitor.UserControls.UListView(); this.statusStrip1 = new System.Windows.Forms.StatusStrip(); this.toolStripStatusLabel1 = new System.Windows.Forms.ToolStripStatusLabel(); this.stripHost = new System.Windows.Forms.ToolStripStatusLabel(); @@ -117,8 +117,6 @@ this.桌面记录查看ToolStripMenuItem = new System.Windows.Forms.ToolStripMenuItem(); this.锁定ToolStripMenuItem = new System.Windows.Forms.ToolStripMenuItem(); this.toolStripMenuItem3 = new System.Windows.Forms.ToolStripMenuItem(); - this.logList = new SiMay.RemoteMonitor.UserControls.UListView(); - this.onlineList = new SiMay.RemoteMonitor.UserControls.UListView(); this.CmdContext.SuspendLayout(); this.logsContext.SuspendLayout(); ((System.ComponentModel.ISupportInitialize)(this.splitContainer1)).BeginInit(); @@ -126,9 +124,8 @@ this.splitContainer1.Panel2.SuspendLayout(); this.splitContainer1.SuspendLayout(); this.panel1.SuspendLayout(); - ((System.ComponentModel.ISupportInitialize)(this.deskrefreshTimeSpan)).BeginInit(); - ((System.ComponentModel.ISupportInitialize)(this.rowtrackBar)).BeginInit(); ((System.ComponentModel.ISupportInitialize)(this.columntrackBar)).BeginInit(); + ((System.ComponentModel.ISupportInitialize)(this.rowtrackBar)).BeginInit(); ((System.ComponentModel.ISupportInitialize)(this.splitContainer2)).BeginInit(); this.splitContainer2.Panel1.SuspendLayout(); this.splitContainer2.Panel2.SuspendLayout(); @@ -433,17 +430,15 @@ this.panel1.Controls.Add(this.linkLabel2); this.panel1.Controls.Add(this.label3); this.panel1.Controls.Add(this.groupBox); - this.panel1.Controls.Add(this.label2); - this.panel1.Controls.Add(this.deskrefreshTimeSpan); this.panel1.Controls.Add(this.button2); this.panel1.Controls.Add(this.button1); this.panel1.Controls.Add(this.column); this.panel1.Controls.Add(this.fsd); this.panel1.Controls.Add(this.row); - this.panel1.Controls.Add(this.rowtrackBar); + this.panel1.Controls.Add(this.columntrackBar); this.panel1.Controls.Add(this.linkLabel1); this.panel1.Controls.Add(this.label1); - this.panel1.Controls.Add(this.columntrackBar); + this.panel1.Controls.Add(this.rowtrackBar); this.panel1.Dock = System.Windows.Forms.DockStyle.Bottom; this.panel1.Location = new System.Drawing.Point(0, 567); this.panel1.Margin = new System.Windows.Forms.Padding(4); @@ -462,12 +457,13 @@ this.linkLabel2.TabIndex = 13; this.linkLabel2.TabStop = true; this.linkLabel2.Text = "视图设置"; + this.linkLabel2.LinkClicked += new System.Windows.Forms.LinkLabelLinkClickedEventHandler(this.linkLabel2_LinkClicked); // // label3 // this.label3.Anchor = ((System.Windows.Forms.AnchorStyles)((System.Windows.Forms.AnchorStyles.Bottom | System.Windows.Forms.AnchorStyles.Right))); this.label3.AutoSize = true; - this.label3.Location = new System.Drawing.Point(553, 6); + this.label3.Location = new System.Drawing.Point(721, 8); this.label3.Margin = new System.Windows.Forms.Padding(4, 0, 4, 0); this.label3.Name = "label3"; this.label3.Size = new System.Drawing.Size(45, 15); @@ -482,55 +478,13 @@ this.groupBox.FormattingEnabled = true; this.groupBox.Items.AddRange(new object[] { "全部"}); - this.groupBox.Location = new System.Drawing.Point(601, 2); + this.groupBox.Location = new System.Drawing.Point(769, 4); this.groupBox.Margin = new System.Windows.Forms.Padding(4); this.groupBox.Name = "groupBox"; this.groupBox.Size = new System.Drawing.Size(152, 23); this.groupBox.TabIndex = 11; this.groupBox.SelectedIndexChanged += new System.EventHandler(this.GroupBox_SelectedIndexChanged); // - // label2 - // - this.label2.Anchor = ((System.Windows.Forms.AnchorStyles)((System.Windows.Forms.AnchorStyles.Bottom | System.Windows.Forms.AnchorStyles.Right))); - this.label2.AutoSize = true; - this.label2.Location = new System.Drawing.Point(763, 8); - this.label2.Margin = new System.Windows.Forms.Padding(4, 0, 4, 0); - this.label2.Name = "label2"; - this.label2.Size = new System.Drawing.Size(75, 15); - this.label2.TabIndex = 10; - this.label2.Text = "刷新间隔:"; - // - // deskrefreshTimeSpan - // - this.deskrefreshTimeSpan.Anchor = ((System.Windows.Forms.AnchorStyles)((System.Windows.Forms.AnchorStyles.Bottom | System.Windows.Forms.AnchorStyles.Right))); - this.deskrefreshTimeSpan.Increment = new decimal(new int[] { - 100, - 0, - 0, - 0}); - this.deskrefreshTimeSpan.Location = new System.Drawing.Point(843, 2); - this.deskrefreshTimeSpan.Margin = new System.Windows.Forms.Padding(4); - this.deskrefreshTimeSpan.Maximum = new decimal(new int[] { - 10000, - 0, - 0, - 0}); - this.deskrefreshTimeSpan.Minimum = new decimal(new int[] { - 300, - 0, - 0, - 0}); - this.deskrefreshTimeSpan.Name = "deskrefreshTimeSpan"; - this.deskrefreshTimeSpan.ReadOnly = true; - this.deskrefreshTimeSpan.Size = new System.Drawing.Size(63, 25); - this.deskrefreshTimeSpan.TabIndex = 9; - this.deskrefreshTimeSpan.TextAlign = System.Windows.Forms.HorizontalAlignment.Center; - this.deskrefreshTimeSpan.Value = new decimal(new int[] { - 300, - 0, - 0, - 0}); - // // button2 // this.button2.Location = new System.Drawing.Point(88, 2); @@ -557,49 +511,49 @@ // this.column.Anchor = ((System.Windows.Forms.AnchorStyles)((System.Windows.Forms.AnchorStyles.Bottom | System.Windows.Forms.AnchorStyles.Right))); this.column.AutoSize = true; - this.column.Location = new System.Drawing.Point(1267, 8); + this.column.Location = new System.Drawing.Point(1283, 8); this.column.Margin = new System.Windows.Forms.Padding(4, 0, 4, 0); this.column.Name = "column"; - this.column.Size = new System.Drawing.Size(31, 15); + this.column.Size = new System.Drawing.Size(15, 15); this.column.TabIndex = 6; - this.column.Text = "150"; + this.column.Text = "3"; // // fsd // this.fsd.Anchor = ((System.Windows.Forms.AnchorStyles)((System.Windows.Forms.AnchorStyles.Bottom | System.Windows.Forms.AnchorStyles.Right))); this.fsd.AutoSize = true; - this.fsd.Location = new System.Drawing.Point(913, 8); + this.fsd.Location = new System.Drawing.Point(929, 8); this.fsd.Margin = new System.Windows.Forms.Padding(4, 0, 4, 0); this.fsd.Name = "fsd"; - this.fsd.Size = new System.Drawing.Size(45, 15); + this.fsd.Size = new System.Drawing.Size(60, 15); this.fsd.TabIndex = 5; - this.fsd.Text = "宽度:"; + this.fsd.Text = "视图列:"; // // row // this.row.Anchor = ((System.Windows.Forms.AnchorStyles)((System.Windows.Forms.AnchorStyles.Bottom | System.Windows.Forms.AnchorStyles.Right))); this.row.AutoSize = true; - this.row.Location = new System.Drawing.Point(1071, 8); + this.row.Location = new System.Drawing.Point(1087, 8); this.row.Margin = new System.Windows.Forms.Padding(4, 0, 4, 0); this.row.Name = "row"; - this.row.Size = new System.Drawing.Size(31, 15); + this.row.Size = new System.Drawing.Size(15, 15); this.row.TabIndex = 4; - this.row.Text = "150"; + this.row.Text = "4"; // - // rowtrackBar + // columntrackBar // - this.rowtrackBar.Anchor = ((System.Windows.Forms.AnchorStyles)((System.Windows.Forms.AnchorStyles.Bottom | System.Windows.Forms.AnchorStyles.Right))); - this.rowtrackBar.AutoSize = false; - this.rowtrackBar.Location = new System.Drawing.Point(956, 6); - this.rowtrackBar.Margin = new System.Windows.Forms.Padding(4); - this.rowtrackBar.Maximum = 1000; - this.rowtrackBar.Minimum = 1; - this.rowtrackBar.Name = "rowtrackBar"; - this.rowtrackBar.Size = new System.Drawing.Size(120, 21); - this.rowtrackBar.TabIndex = 3; - this.rowtrackBar.TickStyle = System.Windows.Forms.TickStyle.None; - this.rowtrackBar.Value = 170; - this.rowtrackBar.Scroll += new System.EventHandler(this.RowtrackBar_Scroll); + this.columntrackBar.Anchor = ((System.Windows.Forms.AnchorStyles)((System.Windows.Forms.AnchorStyles.Bottom | System.Windows.Forms.AnchorStyles.Right))); + this.columntrackBar.AutoSize = false; + this.columntrackBar.Location = new System.Drawing.Point(1000, 6); + this.columntrackBar.Margin = new System.Windows.Forms.Padding(4); + this.columntrackBar.Maximum = 50; + this.columntrackBar.Minimum = 1; + this.columntrackBar.Name = "columntrackBar"; + this.columntrackBar.Size = new System.Drawing.Size(95, 21); + this.columntrackBar.TabIndex = 3; + this.columntrackBar.TickStyle = System.Windows.Forms.TickStyle.None; + this.columntrackBar.Value = 4; + this.columntrackBar.Scroll += new System.EventHandler(this.RowtrackBar_Scroll); // // linkLabel1 // @@ -618,27 +572,27 @@ // this.label1.Anchor = ((System.Windows.Forms.AnchorStyles)((System.Windows.Forms.AnchorStyles.Bottom | System.Windows.Forms.AnchorStyles.Right))); this.label1.AutoSize = true; - this.label1.Location = new System.Drawing.Point(1113, 8); + this.label1.Location = new System.Drawing.Point(1118, 8); this.label1.Margin = new System.Windows.Forms.Padding(4, 0, 4, 0); this.label1.Name = "label1"; - this.label1.Size = new System.Drawing.Size(45, 15); + this.label1.Size = new System.Drawing.Size(60, 15); this.label1.TabIndex = 1; - this.label1.Text = "高度:"; + this.label1.Text = "视图行:"; // - // columntrackBar + // rowtrackBar // - this.columntrackBar.Anchor = ((System.Windows.Forms.AnchorStyles)((System.Windows.Forms.AnchorStyles.Bottom | System.Windows.Forms.AnchorStyles.Right))); - this.columntrackBar.AutoSize = false; - this.columntrackBar.Location = new System.Drawing.Point(1152, 6); - this.columntrackBar.Margin = new System.Windows.Forms.Padding(4); - this.columntrackBar.Maximum = 1000; - this.columntrackBar.Minimum = 1; - this.columntrackBar.Name = "columntrackBar"; - this.columntrackBar.Size = new System.Drawing.Size(120, 21); - this.columntrackBar.TabIndex = 0; - this.columntrackBar.TickStyle = System.Windows.Forms.TickStyle.None; - this.columntrackBar.Value = 150; - this.columntrackBar.Scroll += new System.EventHandler(this.ColumntrackBar_Scroll); + this.rowtrackBar.Anchor = ((System.Windows.Forms.AnchorStyles)((System.Windows.Forms.AnchorStyles.Bottom | System.Windows.Forms.AnchorStyles.Right))); + this.rowtrackBar.AutoSize = false; + this.rowtrackBar.Location = new System.Drawing.Point(1185, 6); + this.rowtrackBar.Margin = new System.Windows.Forms.Padding(4); + this.rowtrackBar.Maximum = 50; + this.rowtrackBar.Minimum = 1; + this.rowtrackBar.Name = "rowtrackBar"; + this.rowtrackBar.Size = new System.Drawing.Size(102, 21); + this.rowtrackBar.TabIndex = 0; + this.rowtrackBar.TickStyle = System.Windows.Forms.TickStyle.None; + this.rowtrackBar.Value = 3; + this.rowtrackBar.Scroll += new System.EventHandler(this.ColumntrackBar_Scroll); // // splitContainer2 // @@ -684,6 +638,23 @@ this.tabPage2.Text = "运行日志"; this.tabPage2.UseVisualStyleBackColor = true; // + // logList + // + this.logList.BorderStyle = System.Windows.Forms.BorderStyle.None; + this.logList.ContextMenuStrip = this.logsContext; + this.logList.Dock = System.Windows.Forms.DockStyle.Fill; + this.logList.FullRowSelect = true; + this.logList.HideSelection = false; + this.logList.Location = new System.Drawing.Point(4, 4); + this.logList.Margin = new System.Windows.Forms.Padding(4); + this.logList.Name = "logList"; + this.logList.Size = new System.Drawing.Size(352, 190); + this.logList.TabIndex = 0; + this.logList.UseCompatibleStateImageBehavior = false; + this.logList.UseWindowsThemStyle = true; + this.logList.View = System.Windows.Forms.View.Details; + this.logList.MouseEnter += new System.EventHandler(this.logList_MouseEnter); + // // tabControl1 // this.tabControl1.Alignment = System.Windows.Forms.TabAlignment.Bottom; @@ -709,6 +680,24 @@ this.tabPage1.Text = "在线列表"; this.tabPage1.UseVisualStyleBackColor = true; // + // onlineList + // + this.onlineList.BorderStyle = System.Windows.Forms.BorderStyle.None; + this.onlineList.CheckBoxes = true; + this.onlineList.ContextMenuStrip = this.CmdContext; + this.onlineList.Dock = System.Windows.Forms.DockStyle.Fill; + this.onlineList.FullRowSelect = true; + this.onlineList.HideSelection = false; + this.onlineList.Location = new System.Drawing.Point(4, 4); + this.onlineList.Margin = new System.Windows.Forms.Padding(4); + this.onlineList.Name = "onlineList"; + this.onlineList.Size = new System.Drawing.Size(1091, 190); + this.onlineList.TabIndex = 0; + this.onlineList.UseCompatibleStateImageBehavior = false; + this.onlineList.UseWindowsThemStyle = false; + this.onlineList.View = System.Windows.Forms.View.Details; + this.onlineList.MouseEnter += new System.EventHandler(this.onlineList_MouseEnter); + // // statusStrip1 // this.statusStrip1.ImageScalingSize = new System.Drawing.Size(20, 20); @@ -1010,41 +999,6 @@ this.toolStripMenuItem3.Text = "关于程序(&H)"; this.toolStripMenuItem3.Click += new System.EventHandler(this.About); // - // logList - // - this.logList.BorderStyle = System.Windows.Forms.BorderStyle.None; - this.logList.ContextMenuStrip = this.logsContext; - this.logList.Dock = System.Windows.Forms.DockStyle.Fill; - this.logList.FullRowSelect = true; - this.logList.HideSelection = false; - this.logList.Location = new System.Drawing.Point(4, 4); - this.logList.Margin = new System.Windows.Forms.Padding(4); - this.logList.Name = "logList"; - this.logList.Size = new System.Drawing.Size(352, 190); - this.logList.TabIndex = 0; - this.logList.UseCompatibleStateImageBehavior = false; - this.logList.UseWindowsThemStyle = true; - this.logList.View = System.Windows.Forms.View.Details; - this.logList.MouseEnter += new System.EventHandler(this.logList_MouseEnter); - // - // onlineList - // - this.onlineList.BorderStyle = System.Windows.Forms.BorderStyle.None; - this.onlineList.CheckBoxes = true; - this.onlineList.ContextMenuStrip = this.CmdContext; - this.onlineList.Dock = System.Windows.Forms.DockStyle.Fill; - this.onlineList.FullRowSelect = true; - this.onlineList.HideSelection = false; - this.onlineList.Location = new System.Drawing.Point(4, 4); - this.onlineList.Margin = new System.Windows.Forms.Padding(4); - this.onlineList.Name = "onlineList"; - this.onlineList.Size = new System.Drawing.Size(1091, 190); - this.onlineList.TabIndex = 0; - this.onlineList.UseCompatibleStateImageBehavior = false; - this.onlineList.UseWindowsThemStyle = false; - this.onlineList.View = System.Windows.Forms.View.Details; - this.onlineList.MouseEnter += new System.EventHandler(this.onlineList_MouseEnter); - // // MainApplication // this.AutoScaleDimensions = new System.Drawing.SizeF(8F, 15F); @@ -1068,9 +1022,8 @@ this.splitContainer1.ResumeLayout(false); this.panel1.ResumeLayout(false); this.panel1.PerformLayout(); - ((System.ComponentModel.ISupportInitialize)(this.deskrefreshTimeSpan)).EndInit(); - ((System.ComponentModel.ISupportInitialize)(this.rowtrackBar)).EndInit(); ((System.ComponentModel.ISupportInitialize)(this.columntrackBar)).EndInit(); + ((System.ComponentModel.ISupportInitialize)(this.rowtrackBar)).EndInit(); this.splitContainer2.Panel1.ResumeLayout(false); this.splitContainer2.Panel2.ResumeLayout(false); ((System.ComponentModel.ISupportInitialize)(this.splitContainer2)).EndInit(); @@ -1133,13 +1086,13 @@ private System.Windows.Forms.ToolStripMenuItem toolStripMenuItem4; private System.Windows.Forms.ToolStripMenuItem toolStripMenuItem5; private System.Windows.Forms.ToolStripSeparator toolStripSeparator1; - private System.Windows.Forms.TrackBar columntrackBar; + private System.Windows.Forms.TrackBar rowtrackBar; private System.Windows.Forms.Panel panel1; private System.Windows.Forms.Label label1; private System.Windows.Forms.LinkLabel linkLabel1; private System.Windows.Forms.Label fsd; private System.Windows.Forms.Label row; - private System.Windows.Forms.TrackBar rowtrackBar; + private System.Windows.Forms.TrackBar columntrackBar; private System.Windows.Forms.Label column; private System.Windows.Forms.Button button2; private System.Windows.Forms.Button button1; @@ -1164,8 +1117,6 @@ private System.Windows.Forms.ToolStripMenuItem toolStripMenuItem11; private System.Windows.Forms.ToolStripSeparator toolStripSeparator7; private System.Windows.Forms.ToolStripMenuItem 桌面记录查看ToolStripMenuItem; - private System.Windows.Forms.Label label2; - private System.Windows.Forms.NumericUpDown deskrefreshTimeSpan; private System.Windows.Forms.SplitContainer splitContainer2; private System.Windows.Forms.TabControl tabControl2; private System.Windows.Forms.TabPage tabPage2; diff --git a/SiMay.RemoteMonitor/MainApplication/MainApplication.cs b/SiMay.RemoteMonitor/MainApplication/MainApplication.cs index faa9923..85b8658 100644 --- a/SiMay.RemoteMonitor/MainApplication/MainApplication.cs +++ b/SiMay.RemoteMonitor/MainApplication/MainApplication.cs @@ -32,16 +32,16 @@ namespace SiMay.RemoteMonitor.MainApplication private bool _isRun = true; private int _connect_count = 0; - private int _desktopViewHeight = 150; - private int _desktopViewWidth = 250; - private int _deskrefreshTimeSpan = 1500; + //private int _desktopViewHeight = 150; + //private int _desktopViewWidth = 250; + //private int _deskrefreshTimeSpan = 1500; private long _sendTransferredBytes = 0; private long _receiveTransferredBytes = 0; private const string GROUP_ALL = "全部"; private System.Timers.Timer _timer; private System.Timers.Timer _viewCarouselTimer; - private ViewCarouselContext _viewCarouselContext = new ViewCarouselContext(); + private DesktopViewSettingContext _viewCarouselContext = new DesktopViewSettingContext(); private Color _closeScreenColor = Color.FromArgb(127, 175, 219); private ImageList _imgList; @@ -93,16 +93,6 @@ namespace SiMay.RemoteMonitor.MainApplication }; this._timer.Start(); - - if (!int.TryParse(AppConfiguration.DesktopViewHeight, out this._desktopViewHeight)) - this._desktopViewHeight = 220; - - if (!int.TryParse(AppConfiguration.DesktopViewWidth, out this._desktopViewWidth)) - this._desktopViewHeight = 280; - - if (!int.TryParse(AppConfiguration.DesktopRefreshTimeSpan, out this._deskrefreshTimeSpan)) - this._deskrefreshTimeSpan = 1500; - if (AppConfiguration.SessionMode == "1") { this.stripHost.Text = AppConfiguration.ServiceIPAddress; @@ -114,11 +104,10 @@ namespace SiMay.RemoteMonitor.MainApplication this.stripPort.Text = AppConfiguration.Port; } - this.columntrackBar.Value = this._desktopViewHeight; - this.rowtrackBar.Value = this._desktopViewWidth; - this.row.Text = rowtrackBar.Value.ToString(); - this.column.Text = columntrackBar.Value.ToString(); - this.deskrefreshTimeSpan.Value = _deskrefreshTimeSpan; + this.rowtrackBar.Value = this._viewCarouselContext.ViewRow; + this.columntrackBar.Value = this._viewCarouselContext.ViewColum; + this.row.Text = columntrackBar.Value.ToString(); + this.column.Text = rowtrackBar.Value.ToString(); this.splitContainer2.SplitterDistance = (splitContainer2.Width / 4); this.logList.SmallImageList = _imgList; @@ -171,14 +160,12 @@ namespace SiMay.RemoteMonitor.MainApplication LockWindow(); } - _viewCarouselTimer = new System.Timers.Timer(AppConfiguration.CarouselInterval); + _viewCarouselTimer = new System.Timers.Timer(_viewCarouselContext.ViewCarouselInterval); _viewCarouselTimer.Elapsed += ViewCarouselFunc; - //if (AppConfiguration.EnabledCarousel) - _viewCarouselTimer.Start(); + if (_viewCarouselContext.CarouselEnabled) + _viewCarouselTimer.Start(); - _viewCarouselContext.ViewRow = 3; - _viewCarouselContext.ViewColum = 3; } private void desktopViewLayout_Resize(object sender, EventArgs e) { @@ -191,7 +178,7 @@ namespace SiMay.RemoteMonitor.MainApplication var viewCount = _viewCarouselContext.ViewColum * _viewCarouselContext.ViewRow; - var marginalRight = 25 / this._viewCarouselContext.ViewColum; + var marginalRight = (_viewCarouselContext.ViewColum * 9) / this._viewCarouselContext.ViewColum; var width = (this.desktopViewLayout.ClientRectangle.Width / _viewCarouselContext.ViewColum) - marginalRight; var height = (this.desktopViewLayout.ClientRectangle.Height / _viewCarouselContext.ViewRow) - marginalRight; @@ -202,11 +189,9 @@ namespace SiMay.RemoteMonitor.MainApplication if (view is Control control) { - var controlRectangle = control.DisplayRectangle; - if (containerRectangle) - { - - } + var controlRectangle = new Rectangle(control.Left, control.Top, control.Width, control.Height); + view.InVisbleArea = this.WhetherContainsInClientRectangle(containerRectangle, controlRectangle); + Console.WriteLine(view.InVisbleArea + " " + index); } if (view.Width == width && view.Height == height && index++ == viewCount) continue; @@ -218,6 +203,12 @@ namespace SiMay.RemoteMonitor.MainApplication }); } } + + public bool WhetherContainsInClientRectangle(Rectangle containerRect, Rectangle childrect) + { + return childrect.Y + childrect.Height >= containerRect.Y && childrect.Y <= containerRect.Bottom; + } + private void ViewCarouselFunc(object sender, System.Timers.ElapsedEventArgs e) { var viewCount = _viewCarouselContext.ViewColum * _viewCarouselContext.ViewRow; @@ -241,7 +232,7 @@ namespace SiMay.RemoteMonitor.MainApplication /// private void RegisterMessageHandler() { - this._appMainAdapterHandler.ViewRefreshInterval = _deskrefreshTimeSpan; + this._appMainAdapterHandler.ViewRefreshInterval = _viewCarouselContext.ViewFreshInterval; this._appMainAdapterHandler.SynchronizationContext = SynchronizationContext.Current; this._appMainAdapterHandler.OnProxyNotifyHandlerEvent += OnProxyNotify; this._appMainAdapterHandler.OnReceiveHandlerEvent += OnReceiveHandlerEvent; @@ -316,11 +307,7 @@ namespace SiMay.RemoteMonitor.MainApplication private IDesktopView OnCreateDesktopViewHandlerEvent(SessionSyncContext syncContext) { - var view = new UDesktopView(syncContext) - { - Width = _desktopViewWidth, - Height = _desktopViewHeight, - }; + var view = new UDesktopView(syncContext); view.OnDoubleClickEvent += DesktopViewDbClick; this.desktopViewLayout.Controls.Add(view); @@ -709,40 +696,22 @@ namespace SiMay.RemoteMonitor.MainApplication private void linkLabel1_LinkClicked(object sender, LinkLabelLinkClickedEventArgs e) { - if (deskrefreshTimeSpan.Value < 300) - { - this.WriteRuninglog("设置未保存,刷新间隔不能小于300!", "error"); - return; - } - - this._desktopViewHeight = columntrackBar.Value; - this._desktopViewWidth = rowtrackBar.Value; - - AppConfiguration.DesktopViewHeight = _desktopViewHeight.ToString(); - AppConfiguration.DesktopViewWidth = _desktopViewWidth.ToString(); - AppConfiguration.DesktopRefreshTimeSpan = deskrefreshTimeSpan.Value.ToString(); - - this._deskrefreshTimeSpan = (int)deskrefreshTimeSpan.Value; + this._viewCarouselContext.ViewRow = rowtrackBar.Value; + this._viewCarouselContext.ViewColum = columntrackBar.Value; - this._appMainAdapterHandler.ViewRefreshInterval = _deskrefreshTimeSpan; - - foreach (UDesktopView item in desktopViewLayout.Controls) - { - item.Width = _desktopViewWidth; - item.Height = _desktopViewHeight; - } + this.ViewOnResize(); this.WriteRuninglog("设置已保存!", "ok"); } private void RowtrackBar_Scroll(object sender, EventArgs e) { - this.row.Text = rowtrackBar.Value.ToString(); + this.row.Text = columntrackBar.Value.ToString(); } private void ColumntrackBar_Scroll(object sender, EventArgs e) { - this.column.Text = columntrackBar.Value.ToString(); + this.column.Text = rowtrackBar.Value.ToString(); } private void button1_Click(object sender, EventArgs e) @@ -968,6 +937,22 @@ namespace SiMay.RemoteMonitor.MainApplication }); } + private void linkLabel2_LinkClicked(object sender, LinkLabelLinkClickedEventArgs e) + { + var dialog = new DesktopViewWallSettingForm(_viewCarouselContext); + if (dialog.ShowDialog() == DialogResult.OK) + { + _appMainAdapterHandler.ViewRefreshInterval = _viewCarouselContext.ViewFreshInterval; + if (!_viewCarouselContext.CarouselEnabled) + this._viewCarouselTimer.Stop(); + else + { + this._viewCarouselTimer.Interval = _viewCarouselContext.ViewCarouselInterval; + this._viewCarouselTimer.Start(); + } + this.ViewOnResize(); + } + } } } \ No newline at end of file diff --git a/SiMay.RemoteMonitor/SiMay.RemoteMonitor.csproj b/SiMay.RemoteMonitor/SiMay.RemoteMonitor.csproj index 6870e3f..d8353d3 100644 --- a/SiMay.RemoteMonitor/SiMay.RemoteMonitor.csproj +++ b/SiMay.RemoteMonitor/SiMay.RemoteMonitor.csproj @@ -164,7 +164,7 @@ DesktopViewWallSettingForm.cs - + Form -- Gitee From 35b53917b2b827def90daf38dc052ab6ed0925a3 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E6=96=87=E7=8E=8B=E7=8E=8B?= <596461462@qq.com> Date: Thu, 5 Dec 2019 00:50:49 +0800 Subject: [PATCH 03/19] =?UTF-8?q?=E5=B1=8F=E5=B9=95=E8=A7=86=E5=9B=BE?= =?UTF-8?q?=E8=BD=AE=E6=92=AD?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../DesktopViewCarousel/DesktopViewWallSettingForm.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/SiMay.RemoteMonitor/MainApplication/DesktopViewCarousel/DesktopViewWallSettingForm.cs b/SiMay.RemoteMonitor/MainApplication/DesktopViewCarousel/DesktopViewWallSettingForm.cs index c66930d..e814404 100644 --- a/SiMay.RemoteMonitor/MainApplication/DesktopViewCarousel/DesktopViewWallSettingForm.cs +++ b/SiMay.RemoteMonitor/MainApplication/DesktopViewCarousel/DesktopViewWallSettingForm.cs @@ -49,7 +49,7 @@ namespace SiMay.RemoteMonitor.MainApplication private void DesktopViewWallSettingForm_Load(object sender, EventArgs e) { - this.DialogResult = DialogResult.Cancel; + //this.DialogResult = DialogResult.Cancel; this.deskrefreshTimeInterval.Value = this._settingContext.ViewFreshInterval; this.carouselInterval.Value = this._settingContext.ViewCarouselInterval; this.enabled.Checked = this._settingContext.CarouselEnabled; -- Gitee From 754b0e247f0bbdfd53832b5184dcb28ba3b64ec2 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E6=96=87=E7=8E=8B=E7=8E=8B?= <596461462@qq.com> Date: Mon, 13 Jan 2020 23:16:47 +0800 Subject: [PATCH 04/19] =?UTF-8?q?=E5=B1=8F=E5=B9=95=E8=A7=86=E5=9B=BE?= =?UTF-8?q?=E6=9B=B4=E6=96=B0(=E6=9C=AA=E5=AE=8C=E6=88=90)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- SiMay.Basic/RectangleHelper.cs | 17 + SiMay.Basic/SiMay.Basic.csproj | 1 + SiMay.Core/AppJobConstant.cs | 28 ++ SiMay.Core/FileIconUtil.cs | 4 + SiMay.Core/SiMay.Core.csproj | 1 + .../ApplicationService/AudioService.cs | 2 +- .../ApplicationService/FileService.cs | 2 +- .../RegistryEditorService.cs | 2 +- .../ApplicationService/ScreenService.cs | 2 +- .../ApplicationService/ShellService.cs | 7 +- .../ApplicationService/StartupService.cs | 2 +- .../ApplicationService/SystemService.cs | 2 +- .../TcpConnectionService.cs | 2 +- .../ApplicationService/VideoService.cs | 2 +- SiMay.RemoteClient.NewCore/SysUtil.cs | 2 +- SiMay.RemoteControlsCore/AppConfiguration.cs | 18 +- .../AppMainAdapterHandler.cs | 7 +- .../Helper/ServiceCOMHelper.cs | 45 +-- .../Application/AudioApplication.cs | 3 +- .../Application/FileApplication.cs | 2 +- .../Application/RegEditorApplication.cs | 3 +- .../Application/ScreenApplication.cs | 2 +- .../Application/ShellApplication.cs | 5 +- .../Application/StartupApplication.cs | 5 +- .../Application/SystemApplication.cs | 3 +- .../Application/TcpConnectionApplication.cs | 5 +- .../Application/VideoApplication.cs | 3 +- .../Helper/ListViewSortHelper.cs | 299 ++++++++---------- .../AppSettingForm.Designer.cs | 14 +- .../MainApplication/AppSettingForm.cs | 14 +- .../DesktopViewSettingContext.cs | 10 + .../MainApplication.Designer.cs | 200 ++++++------ .../MainApplication/MainApplication.cs | 127 ++++---- .../UserControls/UDesktopView.cs | 1 + SiMay.RemoteMonitor/UserControls/UListView.cs | 19 +- SiMayRemoteManager.sln | 15 - 36 files changed, 444 insertions(+), 432 deletions(-) create mode 100644 SiMay.Basic/RectangleHelper.cs create mode 100644 SiMay.Core/AppJobConstant.cs diff --git a/SiMay.Basic/RectangleHelper.cs b/SiMay.Basic/RectangleHelper.cs new file mode 100644 index 0000000..4c78898 --- /dev/null +++ b/SiMay.Basic/RectangleHelper.cs @@ -0,0 +1,17 @@ +using System; +using System.Collections.Generic; +using System.Drawing; +using System.Linq; +using System.Text; + +namespace SiMay.Basic +{ + public class RectangleHelper + { + public static bool WhetherContainsInDisplayRectangle(Rectangle containerRect, Rectangle childRect) + { + var result = childRect.Y + childRect.Height >= containerRect.Y && childRect.Y <= containerRect.Bottom; + return result; + } + } +} diff --git a/SiMay.Basic/SiMay.Basic.csproj b/SiMay.Basic/SiMay.Basic.csproj index dd39ee2..15cbd87 100644 --- a/SiMay.Basic/SiMay.Basic.csproj +++ b/SiMay.Basic/SiMay.Basic.csproj @@ -57,6 +57,7 @@ + diff --git a/SiMay.Core/AppJobConstant.cs b/SiMay.Core/AppJobConstant.cs new file mode 100644 index 0000000..0e58cc5 --- /dev/null +++ b/SiMay.Core/AppJobConstant.cs @@ -0,0 +1,28 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; + +namespace SiMay.Core +{ + public class AppJobConstant + { + public const string REMOTE_DESKTOP = "RemoteDesktopJob"; + + public const string REMOTE_FILE = "FileManagerJob"; + + public const string REMOTE_AUDIO = "RemoteAudioJob"; + + public const string REMOTE_REGEDIT = "RemoteRegistryEditorJob"; + + public const string REMOTE_SHELL = "RemoteShellJob"; + + public const string REMOTE_STARTUP = "StartupManagerJob"; + + public const string REMOTE_SYSMANAGER = "SystemManagerJob"; + + public const string REMOTE_TCP = "TcpConnectionManagerJob"; + + public const string REMOTE_VIDEO = "RemoteViedoJob"; + } +} diff --git a/SiMay.Core/FileIconUtil.cs b/SiMay.Core/FileIconUtil.cs index 7f35f0c..b6588ae 100644 --- a/SiMay.Core/FileIconUtil.cs +++ b/SiMay.Core/FileIconUtil.cs @@ -36,6 +36,9 @@ namespace SiMay.Core [DllImport("User32.dll", EntryPoint = "DestroyIcon")] public static extern int DestroyIcon(IntPtr hIcon); + [DllImport("ole32.dll")] + public static extern int CoInitialize(IntPtr pvReserved); + //定义文件属性标识 public enum FileAttributeFlags : int { @@ -97,6 +100,7 @@ namespace SiMay.Core { FileInfomation shfi = new FileInfomation(); IntPtr hI; + CoInitialize(IntPtr.Zero); if (isLargeIcon) { hI = SHGetFileInfo(fileExt, 0, ref shfi, (uint)Marshal.SizeOf(shfi), (uint)FileInfoFlags.SHGFI_ICON | (uint)FileInfoFlags.SHGFI_USEFILEATTRIBUTES | (uint)FileInfoFlags.SHGFI_LARGEICON); diff --git a/SiMay.Core/SiMay.Core.csproj b/SiMay.Core/SiMay.Core.csproj index ee68c0c..797bfae 100644 --- a/SiMay.Core/SiMay.Core.csproj +++ b/SiMay.Core/SiMay.Core.csproj @@ -48,6 +48,7 @@ + diff --git a/SiMay.RemoteClient.NewCore/ApplicationService/AudioService.cs b/SiMay.RemoteClient.NewCore/ApplicationService/AudioService.cs index 197164b..51d7883 100644 --- a/SiMay.RemoteClient.NewCore/ApplicationService/AudioService.cs +++ b/SiMay.RemoteClient.NewCore/ApplicationService/AudioService.cs @@ -13,7 +13,7 @@ using WindSound; namespace SiMay.ServiceCore.ApplicationService { [ServiceName("远程语音")] - [ServiceKey("RemoteAudioJob")] + [ServiceKey(AppJobConstant.REMOTE_AUDIO)] public class AudioService : ServiceManagerBase { private bool _isRun = true; diff --git a/SiMay.RemoteClient.NewCore/ApplicationService/FileService.cs b/SiMay.RemoteClient.NewCore/ApplicationService/FileService.cs index c1dbc58..eb97c27 100644 --- a/SiMay.RemoteClient.NewCore/ApplicationService/FileService.cs +++ b/SiMay.RemoteClient.NewCore/ApplicationService/FileService.cs @@ -23,7 +23,7 @@ using static SiMay.ServiceCore.CommonWin32Api; namespace SiMay.ServiceCore.ApplicationService { [ServiceName("文件管理")] - [ServiceKey("FileManagerJob")] + [ServiceKey(AppJobConstant.REMOTE_FILE)] public class FileService : ServiceManagerBase { private const int FILE_BUFFER_SIZE = 1024 * 512; diff --git a/SiMay.RemoteClient.NewCore/ApplicationService/RegistryEditorService.cs b/SiMay.RemoteClient.NewCore/ApplicationService/RegistryEditorService.cs index 4d1cf48..fe83898 100644 --- a/SiMay.RemoteClient.NewCore/ApplicationService/RegistryEditorService.cs +++ b/SiMay.RemoteClient.NewCore/ApplicationService/RegistryEditorService.cs @@ -18,7 +18,7 @@ using System.Text; namespace SiMay.ServiceCore.ApplicationService { [ServiceName("远程注册表")] - [ServiceKey("RemoteRegistryEditorJob")] + [ServiceKey(AppJobConstant.REMOTE_REGEDIT)] public class RegistryEditorService : ServiceManagerBase { [PacketHandler(MessageHead.S_NREG_LOAD_REGKEYS)] diff --git a/SiMay.RemoteClient.NewCore/ApplicationService/ScreenService.cs b/SiMay.RemoteClient.NewCore/ApplicationService/ScreenService.cs index 8fc2847..7a17bb9 100644 --- a/SiMay.RemoteClient.NewCore/ApplicationService/ScreenService.cs +++ b/SiMay.RemoteClient.NewCore/ApplicationService/ScreenService.cs @@ -26,7 +26,7 @@ using System.Linq; namespace SiMay.ServiceCore.ApplicationService { [ServiceName("远程桌面")] - [ServiceKey("RemoteDesktopJob")] + [ServiceKey(AppJobConstant.REMOTE_DESKTOP)] public class ScreenService : ServiceManagerBase { private int _bscanmode = 1; //0差异 1逐行 diff --git a/SiMay.RemoteClient.NewCore/ApplicationService/ShellService.cs b/SiMay.RemoteClient.NewCore/ApplicationService/ShellService.cs index ed29691..170a6a5 100644 --- a/SiMay.RemoteClient.NewCore/ApplicationService/ShellService.cs +++ b/SiMay.RemoteClient.NewCore/ApplicationService/ShellService.cs @@ -14,7 +14,7 @@ using System.IO; namespace SiMay.ServiceCore.ApplicationService { [ServiceName("Shell管理")] - [ServiceKey("RemoteShellJob")] + [ServiceKey(AppJobConstant.REMOTE_SHELL)] public class ShellService : ServiceManagerBase { private Process _pipe; @@ -27,11 +27,6 @@ namespace SiMay.ServiceCore.ApplicationService { _pipe.Kill(); } - - [PacketHandler(MessageHead.S_GLOBAL_ONCLOSE)] - public void CloseSession(TcpSocketSaeaSession session) - => this.CloseSession(); - private void Init() { _pipe = new Process diff --git a/SiMay.RemoteClient.NewCore/ApplicationService/StartupService.cs b/SiMay.RemoteClient.NewCore/ApplicationService/StartupService.cs index d13cddb..032d598 100644 --- a/SiMay.RemoteClient.NewCore/ApplicationService/StartupService.cs +++ b/SiMay.RemoteClient.NewCore/ApplicationService/StartupService.cs @@ -22,7 +22,7 @@ using System.Windows.Forms; namespace SiMay.ServiceCore.ApplicationService { [ServiceName("启动项管理")] - [ServiceKey("StartupManagerJob")] + [ServiceKey(AppJobConstant.REMOTE_STARTUP)] public class StartupService : ServiceManagerBase { [PacketHandler(MessageHead.S_STARTUP_GET_LIST)] diff --git a/SiMay.RemoteClient.NewCore/ApplicationService/SystemService.cs b/SiMay.RemoteClient.NewCore/ApplicationService/SystemService.cs index b3b322b..2ba9f5e 100644 --- a/SiMay.RemoteClient.NewCore/ApplicationService/SystemService.cs +++ b/SiMay.RemoteClient.NewCore/ApplicationService/SystemService.cs @@ -24,7 +24,7 @@ using SiMay.ServiceCore.Win32; namespace SiMay.ServiceCore.ApplicationService { [ServiceName("系统管理")] - [ServiceKey("SystemManagerJob")] + [ServiceKey(AppJobConstant.REMOTE_SYSMANAGER)] public class SystemService : ServiceManagerBase { private ComputerInfo _memoryInfo = new ComputerInfo(); diff --git a/SiMay.RemoteClient.NewCore/ApplicationService/TcpConnectionService.cs b/SiMay.RemoteClient.NewCore/ApplicationService/TcpConnectionService.cs index c5bee4a..cf5677f 100644 --- a/SiMay.RemoteClient.NewCore/ApplicationService/TcpConnectionService.cs +++ b/SiMay.RemoteClient.NewCore/ApplicationService/TcpConnectionService.cs @@ -19,7 +19,7 @@ using System.Text; namespace SiMay.ServiceCore.ApplicationService { [ServiceName("Tcp连接管理")] - [ServiceKey("TcpConnectionManagerJob")] + [ServiceKey(AppJobConstant.REMOTE_TCP)] public class TcpConnectionService : ServiceManagerBase { [PacketHandler(MessageHead.S_TCP_GET_LIST)] diff --git a/SiMay.RemoteClient.NewCore/ApplicationService/VideoService.cs b/SiMay.RemoteClient.NewCore/ApplicationService/VideoService.cs index e2e5aff..afa7156 100644 --- a/SiMay.RemoteClient.NewCore/ApplicationService/VideoService.cs +++ b/SiMay.RemoteClient.NewCore/ApplicationService/VideoService.cs @@ -16,7 +16,7 @@ using System.Threading; namespace SiMay.ServiceCore.ApplicationService { [ServiceName("远程监控摄像头")] - [ServiceKey("RemoteViedoJob")] + [ServiceKey(AppJobConstant.REMOTE_VIDEO)] public class VideoService : ServiceManagerBase { private int qty = 30; diff --git a/SiMay.RemoteClient.NewCore/SysUtil.cs b/SiMay.RemoteClient.NewCore/SysUtil.cs index 3eab3c8..8821d8f 100644 --- a/SiMay.RemoteClient.NewCore/SysUtil.cs +++ b/SiMay.RemoteClient.NewCore/SysUtil.cs @@ -56,7 +56,7 @@ namespace SiMay.ServiceCore var aboutMenu = new ToolStripMenuItem("关于服务"); aboutMenu.MouseDown += (s, e) => { - MessageBoxHelper.ShowBoxExclamation("SiMay远程管理是一款开源的Windows系统远程协助系统,支持远程桌面控制、文件管理、远程语音、远程查看摄像头、远程注册表、远程shell、远程键盘记录等功能,您当前运行的是被控服务程序。", "关于程序"); + MessageBoxHelper.ShowBoxExclamation("SiMay远程管理是一款开源的Windows系统远程协助系统,支持远程桌面、文件管理、远程语音、远程摄像头、远程注册表、远程shell等功能,您当前运行的是被控服务程序。", "关于程序"); }; contextMenus.Items.Add(aboutMenu); contextMenus.Items.Add(exitMenu); diff --git a/SiMay.RemoteControlsCore/AppConfiguration.cs b/SiMay.RemoteControlsCore/AppConfiguration.cs index 2d4da05..f62dd14 100644 --- a/SiMay.RemoteControlsCore/AppConfiguration.cs +++ b/SiMay.RemoteControlsCore/AppConfiguration.cs @@ -67,10 +67,10 @@ namespace SiMay.RemoteControlsCore set { SysConfig.SetConfig("IPAddress", value); } } - public static string Port + public static int Port { - get { return SysConfig.GetConfig("Port"); } - set { SysConfig.SetConfig("Port", value); } + get { return int.Parse(SysConfig.GetConfig("Port")); } + set { SysConfig.SetConfig("Port", value.ToString()); } } public static string ConnectPassWord @@ -79,10 +79,10 @@ namespace SiMay.RemoteControlsCore set { SysConfig.SetConfig("ConnectPassWord", value); } } - public static string MaxConnectCount + public static int MaxConnectCount { - get { return SysConfig.GetConfig("MaxConnectCount"); } - set { SysConfig.SetConfig("MaxConnectCount", value); } + get { return int.Parse(SysConfig.GetConfig("MaxConnectCount")); } + set { SysConfig.SetConfig("MaxConnectCount", value.ToString()); } } public static string WindowMaximize @@ -155,10 +155,10 @@ namespace SiMay.RemoteControlsCore set { SysConfig.SetConfig("ServiceIPAddress", value); } } - public static string ServicePort + public static int ServicePort { - get { return SysConfig.GetConfig("ServicePort"); } - set { SysConfig.SetConfig("ServicePort", value); } + get { return int.Parse(SysConfig.GetConfig("ServicePort")); } + set { SysConfig.SetConfig("ServicePort", value.ToString()); } } public static bool CarouselEnabled diff --git a/SiMay.RemoteControlsCore/AppMainAdapterHandler.cs b/SiMay.RemoteControlsCore/AppMainAdapterHandler.cs index 7acd4ae..06db04f 100644 --- a/SiMay.RemoteControlsCore/AppMainAdapterHandler.cs +++ b/SiMay.RemoteControlsCore/AppMainAdapterHandler.cs @@ -100,12 +100,9 @@ namespace SiMay.RemoteControlsCore ? AppConfiguration.IPAddress : AppConfiguration.ServiceIPAddress; - int port = int.Parse(sessionMode == 0 - ? AppConfiguration.Port - : AppConfiguration.ServicePort); + int port = sessionMode == 0 ? AppConfiguration.Port : AppConfiguration.ServicePort; - if (!int.TryParse(AppConfiguration.MaxConnectCount, out var maxconnectCount)) - maxconnectCount = 0; + int maxconnectCount = AppConfiguration.MaxConnectCount; var options = new SessionProviderOptions { diff --git a/SiMay.RemoteControlsCore/Helper/ServiceCOMHelper.cs b/SiMay.RemoteControlsCore/Helper/ServiceCOMHelper.cs index 97b3217..8fa3363 100644 --- a/SiMay.RemoteControlsCore/Helper/ServiceCOMHelper.cs +++ b/SiMay.RemoteControlsCore/Helper/ServiceCOMHelper.cs @@ -1,4 +1,5 @@ -using SiMay.Core; +using SiMay.Basic; +using SiMay.Core; using SiMay.Core.Packets; using SiMay.Net.SessionProvider.SessionBased; using System; @@ -14,27 +15,27 @@ namespace SiMay.RemoteControlsCore { private static Dictionary ServiceCOMPlugins = new Dictionary(); - static ServiceCOMLoader() - { - //string[] pluginFileNames = new string[] - //{ - // "SiMayServiceCore.dll", - // "SiMay.Core.dll", - // "SiMay.Serialize.dll", - // "SiMay.Basic.dll", - // "AForge.Video.dll", - // "AForge.Video.DirectShow.dll" - //}; + //static ServiceCOMLoader() + //{ + // string[] pluginFileNames = new string[] + // { + // "SiMayServiceCore.dll", + // "SiMay.Core.dll", + // "SiMay.Serialize.dll", + // "SiMay.Basic.dll", + // "AForge.Video.dll", + // "AForge.Video.DirectShow.dll" + // }; - //foreach (var fileName in pluginFileNames) - //{ - // var path = Path.Combine(Environment.CurrentDirectory, "plugins", fileName); - // if (File.Exists(path)) - // ServiceCOMPlugins.Add(fileName, File.ReadAllBytes(path)); - // else - // throw new FileNotFoundException("服务插件缺失:" + fileName); - //} - } + // foreach (var fileName in pluginFileNames) + // { + // var path = Path.Combine(Environment.CurrentDirectory, "plugins", fileName); + // if (File.Exists(path)) + // ServiceCOMPlugins.Add(fileName, File.ReadAllBytes(path)); + // else + // throw new FileNotFoundException("服务插件缺失:" + fileName); + // } + //} /// /// 主连接数据发送函数,使未加载服务插件的被控端加载插件,注意!!非主连接勿用 @@ -44,7 +45,7 @@ namespace SiMay.RemoteControlsCore internal static void SendMessageDoHasCOM(this SessionHandler session, byte[] data) { //var syncContext = session.AppTokens[SysConstants.INDEX_WORKER] as SessionSyncContext; - //if (!syncContext.HasLoadServiceCOM) + //if (!syncContext[SysConstants.HasLoadServiceCOM].ConvertTo()) // SendServicePlugins(session); session.SendAsync(data); } diff --git a/SiMay.RemoteMonitor/Application/AudioApplication.cs b/SiMay.RemoteMonitor/Application/AudioApplication.cs index ea3b46c..4a73535 100644 --- a/SiMay.RemoteMonitor/Application/AudioApplication.cs +++ b/SiMay.RemoteMonitor/Application/AudioApplication.cs @@ -1,4 +1,5 @@ using SiMay.Basic; +using SiMay.Core; using SiMay.RemoteControlsCore; using SiMay.RemoteControlsCore.HandlerAdapters; using SiMay.RemoteMonitor.Attributes; @@ -13,7 +14,7 @@ namespace SiMay.RemoteMonitor.Application [OnTools] [ApplicationName("远程语音")] [AppResourceName("AudioManager")] - [Application(typeof(AudioAdapterHandler), "RemoteAudioJob", 20)] + [Application(typeof(AudioAdapterHandler), AppJobConstant.REMOTE_AUDIO, 20)] public partial class AudioApplication : Form, IApplication { [ApplicationAdapterHandler] diff --git a/SiMay.RemoteMonitor/Application/FileApplication.cs b/SiMay.RemoteMonitor/Application/FileApplication.cs index 46938eb..5810d63 100644 --- a/SiMay.RemoteMonitor/Application/FileApplication.cs +++ b/SiMay.RemoteMonitor/Application/FileApplication.cs @@ -28,7 +28,7 @@ namespace SiMay.RemoteMonitor.Application [OnTools] [ApplicationName("文件管理")] [AppResourceName("FileManager")] - [Application(typeof(RemoteFileAdapterHandler), "FileManagerJob", 10)] + [Application(typeof(RemoteFileAdapterHandler), AppJobConstant.REMOTE_FILE, 10)] public partial class FileApplication : Form, IApplication { private const Int32 IDM_DIR_DESKTOP = 1000; diff --git a/SiMay.RemoteMonitor/Application/RegEditorApplication.cs b/SiMay.RemoteMonitor/Application/RegEditorApplication.cs index 2492789..4fa53a3 100644 --- a/SiMay.RemoteMonitor/Application/RegEditorApplication.cs +++ b/SiMay.RemoteMonitor/Application/RegEditorApplication.cs @@ -4,6 +4,7 @@ using System.Drawing; using System.Linq; using System.Windows.Forms; using Microsoft.Win32; +using SiMay.Core; using SiMay.Core.Common; using SiMay.Core.Extensions; using SiMay.Core.Packets.RegEdit; @@ -17,7 +18,7 @@ namespace SiMay.RemoteMonitor.Application [OnTools] [ApplicationName("注册表管理")] [AppResourceName("RegEditManager")] - [Application(typeof(RegistryEditorAdapterHandler), "RemoteRegistryEditorJob", 50)] + [Application(typeof(RegistryEditorAdapterHandler), AppJobConstant.REMOTE_REGEDIT, 50)] public partial class RegEditorApplication : Form, IApplication { protected override CreateParams CreateParams diff --git a/SiMay.RemoteMonitor/Application/ScreenApplication.cs b/SiMay.RemoteMonitor/Application/ScreenApplication.cs index 39940a8..3047526 100644 --- a/SiMay.RemoteMonitor/Application/ScreenApplication.cs +++ b/SiMay.RemoteMonitor/Application/ScreenApplication.cs @@ -20,7 +20,7 @@ namespace SiMay.RemoteMonitor.Application [OnTools] [ApplicationName("远程桌面")] [AppResourceName("ScreenManager")] - [Application(typeof(RemoteScreenAdapterHandler), "RemoteDesktopJob", 0)] + [Application(typeof(RemoteScreenAdapterHandler), AppJobConstant.REMOTE_DESKTOP, 0)] public partial class ScreenApplication : Form, IApplication { private const Int32 IDM_SCREENMON = 1000; diff --git a/SiMay.RemoteMonitor/Application/ShellApplication.cs b/SiMay.RemoteMonitor/Application/ShellApplication.cs index 6803b18..bdd55ed 100644 --- a/SiMay.RemoteMonitor/Application/ShellApplication.cs +++ b/SiMay.RemoteMonitor/Application/ShellApplication.cs @@ -1,4 +1,5 @@ -using SiMay.RemoteControlsCore; +using SiMay.Core; +using SiMay.RemoteControlsCore; using SiMay.RemoteControlsCore.HandlerAdapters; using SiMay.RemoteMonitor.Attributes; using System; @@ -10,7 +11,7 @@ namespace SiMay.RemoteMonitor.Application [OnTools] [ApplicationName("远程终端")] [AppResourceName("ShellManager")] - [Application(typeof(ShellAdapterHandler), "RemoteShellJob", 60)] + [Application(typeof(ShellAdapterHandler), AppJobConstant.REMOTE_SHELL, 60)] public partial class ShellApplication : Form, IApplication { diff --git a/SiMay.RemoteMonitor/Application/StartupApplication.cs b/SiMay.RemoteMonitor/Application/StartupApplication.cs index b8a5e7c..bc04fae 100644 --- a/SiMay.RemoteMonitor/Application/StartupApplication.cs +++ b/SiMay.RemoteMonitor/Application/StartupApplication.cs @@ -1,4 +1,5 @@ -using SiMay.Core.Enums; +using SiMay.Core; +using SiMay.Core.Enums; using SiMay.Core.Packets.Startup; using SiMay.RemoteControlsCore; using SiMay.RemoteControlsCore.HandlerAdapters; @@ -16,7 +17,7 @@ using System.Windows.Forms; namespace SiMay.RemoteMonitor.Application { [ApplicationName("启动项管理")] - [Application(typeof(StartupAdapterHandler), "StartupManagerJob", 100)] + [Application(typeof(StartupAdapterHandler), AppJobConstant.REMOTE_STARTUP, 100)] public partial class StartupApplication : Form, IApplication { [ApplicationAdapterHandler] diff --git a/SiMay.RemoteMonitor/Application/SystemApplication.cs b/SiMay.RemoteMonitor/Application/SystemApplication.cs index 91623cb..e94b1b5 100644 --- a/SiMay.RemoteMonitor/Application/SystemApplication.cs +++ b/SiMay.RemoteMonitor/Application/SystemApplication.cs @@ -1,4 +1,5 @@ using SiMay.Basic; +using SiMay.Core; using SiMay.Core.Packets; using SiMay.RemoteControlsCore; using SiMay.RemoteControlsCore.HandlerAdapters; @@ -17,7 +18,7 @@ namespace SiMay.RemoteMonitor.Application [OnTools] [ApplicationName("系统管理")] [AppResourceName("SystemManager")] - [Application(typeof(SystemAdapterHandler), "SystemManagerJob", 70)] + [Application(typeof(SystemAdapterHandler), AppJobConstant.REMOTE_SYSMANAGER, 70)] public partial class SystemApplication : Form, IApplication { private string _title = "//系统管理 #Name#"; diff --git a/SiMay.RemoteMonitor/Application/TcpConnectionApplication.cs b/SiMay.RemoteMonitor/Application/TcpConnectionApplication.cs index 8e0974a..910c468 100644 --- a/SiMay.RemoteMonitor/Application/TcpConnectionApplication.cs +++ b/SiMay.RemoteMonitor/Application/TcpConnectionApplication.cs @@ -1,4 +1,5 @@ -using SiMay.Core.Packets.TcpConnection; +using SiMay.Core; +using SiMay.Core.Packets.TcpConnection; using SiMay.RemoteControlsCore; using SiMay.RemoteControlsCore.HandlerAdapters; using SiMay.RemoteMonitor.Attributes; @@ -9,7 +10,7 @@ using System.Windows.Forms; namespace SiMay.RemoteMonitor.Application { [ApplicationName("Tcp连接管理")] - [Application(typeof(TcpConnectionAdapterHandler), "TcpConnectionManagerJob", 90)] + [Application(typeof(TcpConnectionAdapterHandler), AppJobConstant.REMOTE_TCP, 90)] public partial class TcpConnectionApplication : Form, IApplication { [ApplicationAdapterHandler] diff --git a/SiMay.RemoteMonitor/Application/VideoApplication.cs b/SiMay.RemoteMonitor/Application/VideoApplication.cs index 978ccb5..46b19f7 100644 --- a/SiMay.RemoteMonitor/Application/VideoApplication.cs +++ b/SiMay.RemoteMonitor/Application/VideoApplication.cs @@ -1,4 +1,5 @@ using SiMay.Basic; +using SiMay.Core; using SiMay.RemoteControlsCore; using SiMay.RemoteControlsCore.HandlerAdapters; using SiMay.RemoteMonitor.Attributes; @@ -16,7 +17,7 @@ namespace SiMay.RemoteMonitor.Application [OnTools] [ApplicationName("视频监控")] [AppResourceName("ViedoManager")] - [Application(typeof(VideoAppAdapterHandler), "RemoteViedoJob", 30)] + [Application(typeof(VideoAppAdapterHandler), AppJobConstant.REMOTE_VIDEO, 30)] public partial class VideoApplication : Form, IApplication { private string _title = "//视频监控 #Name#"; diff --git a/SiMay.RemoteMonitor/Helper/ListViewSortHelper.cs b/SiMay.RemoteMonitor/Helper/ListViewSortHelper.cs index f8ed5cb..2435fc8 100644 --- a/SiMay.RemoteMonitor/Helper/ListViewSortHelper.cs +++ b/SiMay.RemoteMonitor/Helper/ListViewSortHelper.cs @@ -6,213 +6,168 @@ using System.Threading.Tasks; namespace SiMay.RemoteMonitor.Entitys { - using System; - using System.Collections; - using System.Windows.Forms; - namespace Common + /// + /// 继承自IComparer + /// + public class ListViewColumnSorter : System.Collections.IComparer { /// - /// 对ListView点击列标题自动排序功能 + /// 指定按照哪个列排序 /// - public class ListViewHelper + private int ColumnToSort; + /// + /// 指定排序的方式 + /// + private System.Windows.Forms.SortOrder OrderOfSort; + /// + /// 声明CaseInsensitiveComparer类对象 + /// + private System.Collections.CaseInsensitiveComparer ObjectCompare; + /// + /// 构造函数 + /// + public ListViewColumnSorter() + { + // 默认按第一列排序 + ColumnToSort = 0; + // 排序方式为不排序 + OrderOfSort = System.Windows.Forms.SortOrder.None; + // 初始化CaseInsensitiveComparer类对象 + ObjectCompare = new System.Collections.CaseInsensitiveComparer(); + } + /// + /// 重写IComparer接口. + /// + /// 要比较的第一个对象 + /// 要比较的第二个对象 + /// 比较的结果.如果相等返回0,如果x大于y返回1,如果x小于y返回-1 + public int Compare(object x, object y) { - /// - /// 构造函数 - /// - public ListViewHelper() + int compareResult; + System.Windows.Forms.ListViewItem listviewX, listviewY; + // 将比较对象转换为ListViewItem对象 + listviewX = (System.Windows.Forms.ListViewItem)x; + listviewY = (System.Windows.Forms.ListViewItem)y; + string xText = listviewX.SubItems[SortColumn].Text; + string yText = listviewY.SubItems[SortColumn].Text; + int xInt, yInt; + // 比较,如果值为IP地址,则根据IP地址的规则排序。 + if (IsIP(xText) && IsIP(yText)) { - // - // TODO: 在此处添加构造函数逻辑 - // + compareResult = CompareIp(xText, yText); } - public static void ListView_ColumnClick(object sender, System.Windows.Forms.ColumnClickEventArgs e) + else if (int.TryParse(xText, out xInt) && int.TryParse(yText, out yInt)) //是否全为数字 { - System.Windows.Forms.ListView lv = sender as System.Windows.Forms.ListView; - // 检查点击的列是不是现在的排序列. - if (e.Column == (lv.ListViewItemSorter as ListViewColumnSorter).SortColumn) - { - // 重新设置此列的排序方法. - if ((lv.ListViewItemSorter as ListViewColumnSorter).Order == System.Windows.Forms.SortOrder.Ascending) - { - (lv.ListViewItemSorter as ListViewColumnSorter).Order = System.Windows.Forms.SortOrder.Descending; - } - else - { - (lv.ListViewItemSorter as ListViewColumnSorter).Order = System.Windows.Forms.SortOrder.Ascending; - } - } - else - { - // 设置排序列,默认为正向排序 - (lv.ListViewItemSorter as ListViewColumnSorter).SortColumn = e.Column; - (lv.ListViewItemSorter as ListViewColumnSorter).Order = System.Windows.Forms.SortOrder.Ascending; - } - // 用新的排序方法对ListView排序 - ((System.Windows.Forms.ListView)sender).Sort(); + //比较数字 + compareResult = CompareInt(xInt, yInt); + } + else + { + //比较对象 + compareResult = ObjectCompare.Compare(xText, yText); + } + // 根据上面的比较结果返回正确的比较结果 + if (OrderOfSort == System.Windows.Forms.SortOrder.Ascending) + { + // 因为是正序排序,所以直接返回结果 + return compareResult; + } + else if (OrderOfSort == System.Windows.Forms.SortOrder.Descending) + { + // 如果是反序排序,所以要取负值再返回 + return (-compareResult); + } + else + { + // 如果相等返回0 + return 0; } } /// - /// 继承自IComparer + /// 判断是否为正确的IP地址,IP范围(0.0.0.0~255.255.255) /// - public class ListViewColumnSorter : System.Collections.IComparer + /// 需验证的IP地址 + /// + public bool IsIP(String ip) { - /// - /// 指定按照哪个列排序 - /// - private int ColumnToSort; - /// - /// 指定排序的方式 - /// - private System.Windows.Forms.SortOrder OrderOfSort; - /// - /// 声明CaseInsensitiveComparer类对象 - /// - private System.Collections.CaseInsensitiveComparer ObjectCompare; - /// - /// 构造函数 - /// - public ListViewColumnSorter() + return System.Text.RegularExpressions.Regex.Match(ip, @"^(25[0-5]|2[0-4][0-9]|[0-1]{1}[0-9]{2}|[1-9]{1}[0-9]{1}|[1-9]|0)\.(25[0-5]|2[0-4][0-9]|[0-1]{1}[0-9]{2}|[1-9]{1}[0-9]{1}|[1-9]|0)\.(25[0-5]|2[0-4][0-9]|[0-1]{1}[0-9]{2}|[1-9]{1}[0-9]{1}|[1-9]|0)\.(25[0-5]|2[0-4][0-9]|[0-1]{1}[0-9]{2}|[1-9]{1}[0-9]{1}|[0-9])$").Success; + } + /// + /// 比较两个数字的大小 + /// + /// 要比较的第一个对象 + /// 要比较的第二个对象 + /// 比较的结果.如果相等返回0,如果x大于y返回1,如果x小于y返回-1 + private int CompareInt(int x, int y) + { + if (x > y) { - // 默认按第一列排序 - ColumnToSort = 0; - // 排序方式为不排序 - OrderOfSort = System.Windows.Forms.SortOrder.None; - // 初始化CaseInsensitiveComparer类对象 - ObjectCompare = new System.Collections.CaseInsensitiveComparer(); + return 1; } - /// - /// 重写IComparer接口. - /// - /// 要比较的第一个对象 - /// 要比较的第二个对象 - /// 比较的结果.如果相等返回0,如果x大于y返回1,如果x小于y返回-1 - public int Compare(object x, object y) + else if (x < y) { - int compareResult; - System.Windows.Forms.ListViewItem listviewX, listviewY; - // 将比较对象转换为ListViewItem对象 - listviewX = (System.Windows.Forms.ListViewItem)x; - listviewY = (System.Windows.Forms.ListViewItem)y; - string xText = listviewX.SubItems[ColumnToSort].Text; - string yText = listviewY.SubItems[ColumnToSort].Text; - int xInt, yInt; - // 比较,如果值为IP地址,则根据IP地址的规则排序。 - if (IsIP(xText) && IsIP(yText)) - { - compareResult = CompareIp(xText, yText); - } - else if (int.TryParse(xText, out xInt) && int.TryParse(yText, out yInt)) //是否全为数字 - { - //比较数字 - compareResult = CompareInt(xInt, yInt); - } - else - { - //比较对象 - compareResult = ObjectCompare.Compare(xText, yText); - } - // 根据上面的比较结果返回正确的比较结果 - if (OrderOfSort == System.Windows.Forms.SortOrder.Ascending) - { - // 因为是正序排序,所以直接返回结果 - return compareResult; - } - else if (OrderOfSort == System.Windows.Forms.SortOrder.Descending) - { - // 如果是反序排序,所以要取负值再返回 - return (-compareResult); - } - else - { - // 如果相等返回0 - return 0; - } + return -1; } - /// - /// 判断是否为正确的IP地址,IP范围(0.0.0.0~255.255.255) - /// - /// 需验证的IP地址 - /// - public bool IsIP(String ip) + else { - return System.Text.RegularExpressions.Regex.Match(ip, @"^(25[0-5]|2[0-4][0-9]|[0-1]{1}[0-9]{2}|[1-9]{1}[0-9]{1}|[1-9]|0)\.(25[0-5]|2[0-4][0-9]|[0-1]{1}[0-9]{2}|[1-9]{1}[0-9]{1}|[1-9]|0)\.(25[0-5]|2[0-4][0-9]|[0-1]{1}[0-9]{2}|[1-9]{1}[0-9]{1}|[1-9]|0)\.(25[0-5]|2[0-4][0-9]|[0-1]{1}[0-9]{2}|[1-9]{1}[0-9]{1}|[0-9])$").Success; + return 0; } - /// - /// 比较两个数字的大小 - /// - /// 要比较的第一个对象 - /// 要比较的第二个对象 - /// 比较的结果.如果相等返回0,如果x大于y返回1,如果x小于y返回-1 - private int CompareInt(int x, int y) + } + /// + /// 比较两个IP地址的大小 + /// + /// 要比较的第一个对象 + /// 要比较的第二个对象 + /// 比较的结果.如果相等返回0,如果x大于y返回1,如果x小于y返回-1 + private int CompareIp(string ipx, string ipy) + { + string[] ipxs = ipx.Split('.'); + string[] ipys = ipy.Split('.'); + for (int i = 0; i < 4; i++) { - if (x > y) + if (Convert.ToInt32(ipxs[i]) > Convert.ToInt32(ipys[i])) { return 1; } - else if (x < y) + else if (Convert.ToInt32(ipxs[i]) < Convert.ToInt32(ipys[i])) { return -1; } else { - return 0; + continue; } } - /// - /// 比较两个IP地址的大小 - /// - /// 要比较的第一个对象 - /// 要比较的第二个对象 - /// 比较的结果.如果相等返回0,如果x大于y返回1,如果x小于y返回-1 - private int CompareIp(string ipx, string ipy) + return 0; + } + /// + /// 获取或设置按照哪一列排序. + /// + public int SortColumn + { + set { - string[] ipxs = ipx.Split('.'); - string[] ipys = ipy.Split('.'); - for (int i = 0; i < 4; i++) - { - if (Convert.ToInt32(ipxs[i]) > Convert.ToInt32(ipys[i])) - { - return 1; - } - else if (Convert.ToInt32(ipxs[i]) < Convert.ToInt32(ipys[i])) - { - return -1; - } - else - { - continue; - } - } - return 0; + ColumnToSort = value; } - /// - /// 获取或设置按照哪一列排序. - /// - public int SortColumn + get { - set - { - ColumnToSort = value; - } - get - { - return ColumnToSort; - } + return ColumnToSort; } - /// - /// 获取或设置排序方式. - /// - public System.Windows.Forms.SortOrder Order + } + /// + /// 获取或设置排序方式. + /// + public System.Windows.Forms.SortOrder Order + { + set { - set - { - OrderOfSort = value; - } - get - { - return OrderOfSort; - } + OrderOfSort = value; + } + get + { + return OrderOfSort; } } } + } diff --git a/SiMay.RemoteMonitor/MainApplication/AppSettingForm.Designer.cs b/SiMay.RemoteMonitor/MainApplication/AppSettingForm.Designer.cs index cf4e10b..e7ff0d7 100644 --- a/SiMay.RemoteMonitor/MainApplication/AppSettingForm.Designer.cs +++ b/SiMay.RemoteMonitor/MainApplication/AppSettingForm.Designer.cs @@ -29,7 +29,7 @@ private void InitializeComponent() { this.save = new System.Windows.Forms.Button(); - this.connectNum = new System.Windows.Forms.TextBox(); + this.connectLimitCount = new System.Windows.Forms.TextBox(); this.label3 = new System.Windows.Forms.Label(); this.port = new System.Windows.Forms.TextBox(); this.label2 = new System.Windows.Forms.Label(); @@ -76,10 +76,10 @@ // // connectNum // - this.connectNum.Location = new System.Drawing.Point(185, 135); - this.connectNum.Name = "connectNum"; - this.connectNum.Size = new System.Drawing.Size(115, 21); - this.connectNum.TabIndex = 13; + this.connectLimitCount.Location = new System.Drawing.Point(185, 135); + this.connectLimitCount.Name = "connectNum"; + this.connectLimitCount.Size = new System.Drawing.Size(115, 21); + this.connectLimitCount.TabIndex = 13; // // label3 // @@ -202,7 +202,7 @@ this.panel2.Controls.Add(this.conPwd); this.panel2.Controls.Add(this.label1); this.panel2.Controls.Add(this.label4); - this.panel2.Controls.Add(this.connectNum); + this.panel2.Controls.Add(this.connectLimitCount); this.panel2.Controls.Add(this.label2); this.panel2.Controls.Add(this.label5); this.panel2.Location = new System.Drawing.Point(32, 2); @@ -390,7 +390,7 @@ #endregion private System.Windows.Forms.Button save; - private System.Windows.Forms.TextBox connectNum; + private System.Windows.Forms.TextBox connectLimitCount; private System.Windows.Forms.Label label3; private System.Windows.Forms.TextBox port; private System.Windows.Forms.Label label2; diff --git a/SiMay.RemoteMonitor/MainApplication/AppSettingForm.cs b/SiMay.RemoteMonitor/MainApplication/AppSettingForm.cs index 9fc5d8d..9d506f5 100644 --- a/SiMay.RemoteMonitor/MainApplication/AppSettingForm.cs +++ b/SiMay.RemoteMonitor/MainApplication/AppSettingForm.cs @@ -19,15 +19,15 @@ namespace SiMay.RemoteMonitor.MainApplication private void save_Click(object sender, EventArgs e) { - if (ip.Text == "" || port.Text == "" || connectNum.Text == "" || conPwd.Text == "") + if (ip.Text == "" || port.Text == "" || connectLimitCount.Text == "" || conPwd.Text == "") { MessageBoxHelper.ShowBoxExclamation("请正确完整填写设置,否则可能导致客户端上线失败!"); return; } AppConfiguration.IPAddress = ip.Text; - AppConfiguration.Port = port.Text; - AppConfiguration.MaxConnectCount = connectNum.Text; + AppConfiguration.Port = int.Parse(port.Text); + AppConfiguration.MaxConnectCount = int.Parse(connectLimitCount.Text); AppConfiguration.ConnectPassWord = conPwd.Text; AppConfiguration.DbClickViewExc = (funComboBox.Items[funComboBox.SelectedIndex] as KeyValueItem).Value; AppConfiguration.WindowMaximize = maximizeCheckBox.Checked.ToString(); @@ -35,7 +35,7 @@ namespace SiMay.RemoteMonitor.MainApplication AppConfiguration.AccessKey = accessKey.Text; AppConfiguration.SessionMode = sessionModeList.SelectedIndex.ToString(); AppConfiguration.ServiceIPAddress = txtservice_address.Text; - AppConfiguration.ServicePort = txtservice_port.Text; + AppConfiguration.ServicePort = int.Parse(txtservice_port.Text); DialogResult result = MessageBox.Show("设置完成,是否重启生效设置?", "提示", MessageBoxButtons.OKCancel, MessageBoxIcon.Exclamation); @@ -64,12 +64,12 @@ namespace SiMay.RemoteMonitor.MainApplication ip.Text = AppConfiguration.IPAddress; conPwd.Text = AppConfiguration.ConnectPassWord; - port.Text = AppConfiguration.Port; - connectNum.Text = AppConfiguration.MaxConnectCount; + port.Text = AppConfiguration.Port.ToString(); + connectLimitCount.Text = AppConfiguration.MaxConnectCount.ToString(); pwdTextBox.Text = AppConfiguration.LockPassWord; accessKey.Text = AppConfiguration.AccessKey; txtservice_address.Text = AppConfiguration.ServiceIPAddress; - txtservice_port.Text = AppConfiguration.ServicePort; + txtservice_port.Text = AppConfiguration.ServicePort.ToString(); int index = int.Parse(AppConfiguration.SessionMode); sessionModeList.SelectedIndex = index; diff --git a/SiMay.RemoteMonitor/MainApplication/DesktopViewCarousel/DesktopViewSettingContext.cs b/SiMay.RemoteMonitor/MainApplication/DesktopViewCarousel/DesktopViewSettingContext.cs index db69902..6524a29 100644 --- a/SiMay.RemoteMonitor/MainApplication/DesktopViewCarousel/DesktopViewSettingContext.cs +++ b/SiMay.RemoteMonitor/MainApplication/DesktopViewCarousel/DesktopViewSettingContext.cs @@ -74,6 +74,16 @@ namespace SiMay.RemoteMonitor.MainApplication /// public IList AlwaysViews { get; set; } + /// + /// 视图高 + /// + public int ViewHeight { get; set; } + + /// + /// 视图宽 + /// + public int ViewWidth { get; set; } + /// /// 是否启用轮播 /// diff --git a/SiMay.RemoteMonitor/MainApplication/MainApplication.Designer.cs b/SiMay.RemoteMonitor/MainApplication/MainApplication.Designer.cs index fb4ae7f..b2f90e5 100644 --- a/SiMay.RemoteMonitor/MainApplication/MainApplication.Designer.cs +++ b/SiMay.RemoteMonitor/MainApplication/MainApplication.Designer.cs @@ -29,7 +29,7 @@ private void InitializeComponent() { this.components = new System.ComponentModel.Container(); - this.CmdContext = new System.Windows.Forms.ContextMenuStrip(this.components); + this.cmdContext = new System.Windows.Forms.ContextMenuStrip(this.components); this.toolStripMenuItem11 = new System.Windows.Forms.ToolStripMenuItem(); this.toolStripMenuItem6 = new System.Windows.Forms.ToolStripMenuItem(); this.toolStripMenuItem1 = new System.Windows.Forms.ToolStripMenuItem(); @@ -70,20 +70,18 @@ this.groupBox = new System.Windows.Forms.ComboBox(); this.button2 = new System.Windows.Forms.Button(); this.button1 = new System.Windows.Forms.Button(); - this.column = new System.Windows.Forms.Label(); + this.viewColumn = new System.Windows.Forms.Label(); this.fsd = new System.Windows.Forms.Label(); - this.row = new System.Windows.Forms.Label(); + this.viewRow = new System.Windows.Forms.Label(); this.columntrackBar = new System.Windows.Forms.TrackBar(); this.linkLabel1 = new System.Windows.Forms.LinkLabel(); this.label1 = new System.Windows.Forms.Label(); this.rowtrackBar = new System.Windows.Forms.TrackBar(); - this.splitContainer2 = new System.Windows.Forms.SplitContainer(); + this.splitContainer = new System.Windows.Forms.SplitContainer(); this.tabControl2 = new System.Windows.Forms.TabControl(); this.tabPage2 = new System.Windows.Forms.TabPage(); - this.logList = new SiMay.RemoteMonitor.UserControls.UListView(); this.tabControl1 = new System.Windows.Forms.TabControl(); this.tabPage1 = new System.Windows.Forms.TabPage(); - this.onlineList = new SiMay.RemoteMonitor.UserControls.UListView(); this.statusStrip1 = new System.Windows.Forms.StatusStrip(); this.toolStripStatusLabel1 = new System.Windows.Forms.ToolStripStatusLabel(); this.stripHost = new System.Windows.Forms.ToolStripStatusLabel(); @@ -117,7 +115,9 @@ this.桌面记录查看ToolStripMenuItem = new System.Windows.Forms.ToolStripMenuItem(); this.锁定ToolStripMenuItem = new System.Windows.Forms.ToolStripMenuItem(); this.toolStripMenuItem3 = new System.Windows.Forms.ToolStripMenuItem(); - this.CmdContext.SuspendLayout(); + this.logList = new SiMay.RemoteMonitor.UserControls.UListView(); + this.servicesOnlineList = new SiMay.RemoteMonitor.UserControls.UListView(); + this.cmdContext.SuspendLayout(); this.logsContext.SuspendLayout(); ((System.ComponentModel.ISupportInitialize)(this.splitContainer1)).BeginInit(); this.splitContainer1.Panel1.SuspendLayout(); @@ -126,10 +126,10 @@ this.panel1.SuspendLayout(); ((System.ComponentModel.ISupportInitialize)(this.columntrackBar)).BeginInit(); ((System.ComponentModel.ISupportInitialize)(this.rowtrackBar)).BeginInit(); - ((System.ComponentModel.ISupportInitialize)(this.splitContainer2)).BeginInit(); - this.splitContainer2.Panel1.SuspendLayout(); - this.splitContainer2.Panel2.SuspendLayout(); - this.splitContainer2.SuspendLayout(); + ((System.ComponentModel.ISupportInitialize)(this.splitContainer)).BeginInit(); + this.splitContainer.Panel1.SuspendLayout(); + this.splitContainer.Panel2.SuspendLayout(); + this.splitContainer.SuspendLayout(); this.tabControl2.SuspendLayout(); this.tabPage2.SuspendLayout(); this.tabControl1.SuspendLayout(); @@ -141,8 +141,8 @@ // // CmdContext // - this.CmdContext.ImageScalingSize = new System.Drawing.Size(20, 20); - this.CmdContext.Items.AddRange(new System.Windows.Forms.ToolStripItem[] { + this.cmdContext.ImageScalingSize = new System.Drawing.Size(20, 20); + this.cmdContext.Items.AddRange(new System.Windows.Forms.ToolStripItem[] { this.toolStripMenuItem11, this.toolStripMenuItem6, this.toolStripMenuItem1, @@ -156,10 +156,10 @@ this.toolStripSeparator1, this.选择全部ToolStripMenuItem, this.取消选择ToolStripMenuItem}); - this.CmdContext.Name = "CmdContext"; - this.CmdContext.RenderMode = System.Windows.Forms.ToolStripRenderMode.Professional; - this.CmdContext.Size = new System.Drawing.Size(154, 280); - this.CmdContext.Opening += new System.ComponentModel.CancelEventHandler(this.CmdContext_Opening); + this.cmdContext.Name = "CmdContext"; + this.cmdContext.RenderMode = System.Windows.Forms.ToolStripRenderMode.Professional; + this.cmdContext.Size = new System.Drawing.Size(154, 280); + this.cmdContext.Opening += new System.ComponentModel.CancelEventHandler(this.CmdContext_Opening); // // toolStripMenuItem11 // @@ -407,7 +407,7 @@ // // splitContainer1.Panel2 // - this.splitContainer1.Panel2.Controls.Add(this.splitContainer2); + this.splitContainer1.Panel2.Controls.Add(this.splitContainer); this.splitContainer1.Size = new System.Drawing.Size(1476, 825); this.splitContainer1.SplitterDistance = 597; this.splitContainer1.SplitterWidth = 1; @@ -432,9 +432,9 @@ this.panel1.Controls.Add(this.groupBox); this.panel1.Controls.Add(this.button2); this.panel1.Controls.Add(this.button1); - this.panel1.Controls.Add(this.column); + this.panel1.Controls.Add(this.viewColumn); this.panel1.Controls.Add(this.fsd); - this.panel1.Controls.Add(this.row); + this.panel1.Controls.Add(this.viewRow); this.panel1.Controls.Add(this.columntrackBar); this.panel1.Controls.Add(this.linkLabel1); this.panel1.Controls.Add(this.label1); @@ -450,7 +450,7 @@ // this.linkLabel2.Anchor = ((System.Windows.Forms.AnchorStyles)((System.Windows.Forms.AnchorStyles.Bottom | System.Windows.Forms.AnchorStyles.Right))); this.linkLabel2.AutoSize = true; - this.linkLabel2.Location = new System.Drawing.Point(1396, 8); + this.linkLabel2.Location = new System.Drawing.Point(1765, 8); this.linkLabel2.Margin = new System.Windows.Forms.Padding(4, 0, 4, 0); this.linkLabel2.Name = "linkLabel2"; this.linkLabel2.Size = new System.Drawing.Size(67, 15); @@ -463,7 +463,7 @@ // this.label3.Anchor = ((System.Windows.Forms.AnchorStyles)((System.Windows.Forms.AnchorStyles.Bottom | System.Windows.Forms.AnchorStyles.Right))); this.label3.AutoSize = true; - this.label3.Location = new System.Drawing.Point(721, 8); + this.label3.Location = new System.Drawing.Point(1090, 8); this.label3.Margin = new System.Windows.Forms.Padding(4, 0, 4, 0); this.label3.Name = "label3"; this.label3.Size = new System.Drawing.Size(45, 15); @@ -478,7 +478,7 @@ this.groupBox.FormattingEnabled = true; this.groupBox.Items.AddRange(new object[] { "全部"}); - this.groupBox.Location = new System.Drawing.Point(769, 4); + this.groupBox.Location = new System.Drawing.Point(1138, 4); this.groupBox.Margin = new System.Windows.Forms.Padding(4); this.groupBox.Name = "groupBox"; this.groupBox.Size = new System.Drawing.Size(152, 23); @@ -509,20 +509,20 @@ // // column // - this.column.Anchor = ((System.Windows.Forms.AnchorStyles)((System.Windows.Forms.AnchorStyles.Bottom | System.Windows.Forms.AnchorStyles.Right))); - this.column.AutoSize = true; - this.column.Location = new System.Drawing.Point(1283, 8); - this.column.Margin = new System.Windows.Forms.Padding(4, 0, 4, 0); - this.column.Name = "column"; - this.column.Size = new System.Drawing.Size(15, 15); - this.column.TabIndex = 6; - this.column.Text = "3"; + this.viewColumn.Anchor = ((System.Windows.Forms.AnchorStyles)((System.Windows.Forms.AnchorStyles.Bottom | System.Windows.Forms.AnchorStyles.Right))); + this.viewColumn.AutoSize = true; + this.viewColumn.Location = new System.Drawing.Point(1652, 8); + this.viewColumn.Margin = new System.Windows.Forms.Padding(4, 0, 4, 0); + this.viewColumn.Name = "column"; + this.viewColumn.Size = new System.Drawing.Size(15, 15); + this.viewColumn.TabIndex = 6; + this.viewColumn.Text = "3"; // // fsd // this.fsd.Anchor = ((System.Windows.Forms.AnchorStyles)((System.Windows.Forms.AnchorStyles.Bottom | System.Windows.Forms.AnchorStyles.Right))); this.fsd.AutoSize = true; - this.fsd.Location = new System.Drawing.Point(929, 8); + this.fsd.Location = new System.Drawing.Point(1298, 8); this.fsd.Margin = new System.Windows.Forms.Padding(4, 0, 4, 0); this.fsd.Name = "fsd"; this.fsd.Size = new System.Drawing.Size(60, 15); @@ -531,20 +531,20 @@ // // row // - this.row.Anchor = ((System.Windows.Forms.AnchorStyles)((System.Windows.Forms.AnchorStyles.Bottom | System.Windows.Forms.AnchorStyles.Right))); - this.row.AutoSize = true; - this.row.Location = new System.Drawing.Point(1087, 8); - this.row.Margin = new System.Windows.Forms.Padding(4, 0, 4, 0); - this.row.Name = "row"; - this.row.Size = new System.Drawing.Size(15, 15); - this.row.TabIndex = 4; - this.row.Text = "4"; + this.viewRow.Anchor = ((System.Windows.Forms.AnchorStyles)((System.Windows.Forms.AnchorStyles.Bottom | System.Windows.Forms.AnchorStyles.Right))); + this.viewRow.AutoSize = true; + this.viewRow.Location = new System.Drawing.Point(1456, 8); + this.viewRow.Margin = new System.Windows.Forms.Padding(4, 0, 4, 0); + this.viewRow.Name = "row"; + this.viewRow.Size = new System.Drawing.Size(15, 15); + this.viewRow.TabIndex = 4; + this.viewRow.Text = "4"; // // columntrackBar // this.columntrackBar.Anchor = ((System.Windows.Forms.AnchorStyles)((System.Windows.Forms.AnchorStyles.Bottom | System.Windows.Forms.AnchorStyles.Right))); this.columntrackBar.AutoSize = false; - this.columntrackBar.Location = new System.Drawing.Point(1000, 6); + this.columntrackBar.Location = new System.Drawing.Point(1369, 6); this.columntrackBar.Margin = new System.Windows.Forms.Padding(4); this.columntrackBar.Maximum = 50; this.columntrackBar.Minimum = 1; @@ -559,7 +559,7 @@ // this.linkLabel1.Anchor = ((System.Windows.Forms.AnchorStyles)((System.Windows.Forms.AnchorStyles.Bottom | System.Windows.Forms.AnchorStyles.Right))); this.linkLabel1.AutoSize = true; - this.linkLabel1.Location = new System.Drawing.Point(1316, 8); + this.linkLabel1.Location = new System.Drawing.Point(1685, 8); this.linkLabel1.Margin = new System.Windows.Forms.Padding(4, 0, 4, 0); this.linkLabel1.Name = "linkLabel1"; this.linkLabel1.Size = new System.Drawing.Size(67, 15); @@ -572,7 +572,7 @@ // this.label1.Anchor = ((System.Windows.Forms.AnchorStyles)((System.Windows.Forms.AnchorStyles.Bottom | System.Windows.Forms.AnchorStyles.Right))); this.label1.AutoSize = true; - this.label1.Location = new System.Drawing.Point(1118, 8); + this.label1.Location = new System.Drawing.Point(1487, 8); this.label1.Margin = new System.Windows.Forms.Padding(4, 0, 4, 0); this.label1.Name = "label1"; this.label1.Size = new System.Drawing.Size(60, 15); @@ -583,7 +583,7 @@ // this.rowtrackBar.Anchor = ((System.Windows.Forms.AnchorStyles)((System.Windows.Forms.AnchorStyles.Bottom | System.Windows.Forms.AnchorStyles.Right))); this.rowtrackBar.AutoSize = false; - this.rowtrackBar.Location = new System.Drawing.Point(1185, 6); + this.rowtrackBar.Location = new System.Drawing.Point(1554, 6); this.rowtrackBar.Margin = new System.Windows.Forms.Padding(4); this.rowtrackBar.Maximum = 50; this.rowtrackBar.Minimum = 1; @@ -596,22 +596,22 @@ // // splitContainer2 // - this.splitContainer2.Dock = System.Windows.Forms.DockStyle.Fill; - this.splitContainer2.Location = new System.Drawing.Point(0, 0); - this.splitContainer2.Margin = new System.Windows.Forms.Padding(3, 2, 3, 2); - this.splitContainer2.Name = "splitContainer2"; + this.splitContainer.Dock = System.Windows.Forms.DockStyle.Fill; + this.splitContainer.Location = new System.Drawing.Point(0, 0); + this.splitContainer.Margin = new System.Windows.Forms.Padding(3, 2, 3, 2); + this.splitContainer.Name = "splitContainer2"; // // splitContainer2.Panel1 // - this.splitContainer2.Panel1.Controls.Add(this.tabControl2); + this.splitContainer.Panel1.Controls.Add(this.tabControl2); // // splitContainer2.Panel2 // - this.splitContainer2.Panel2.Controls.Add(this.tabControl1); - this.splitContainer2.Size = new System.Drawing.Size(1476, 227); - this.splitContainer2.SplitterDistance = 368; - this.splitContainer2.SplitterWidth = 1; - this.splitContainer2.TabIndex = 0; + this.splitContainer.Panel2.Controls.Add(this.tabControl1); + this.splitContainer.Size = new System.Drawing.Size(1476, 227); + this.splitContainer.SplitterDistance = 368; + this.splitContainer.SplitterWidth = 1; + this.splitContainer.TabIndex = 0; // // tabControl2 // @@ -638,23 +638,6 @@ this.tabPage2.Text = "运行日志"; this.tabPage2.UseVisualStyleBackColor = true; // - // logList - // - this.logList.BorderStyle = System.Windows.Forms.BorderStyle.None; - this.logList.ContextMenuStrip = this.logsContext; - this.logList.Dock = System.Windows.Forms.DockStyle.Fill; - this.logList.FullRowSelect = true; - this.logList.HideSelection = false; - this.logList.Location = new System.Drawing.Point(4, 4); - this.logList.Margin = new System.Windows.Forms.Padding(4); - this.logList.Name = "logList"; - this.logList.Size = new System.Drawing.Size(352, 190); - this.logList.TabIndex = 0; - this.logList.UseCompatibleStateImageBehavior = false; - this.logList.UseWindowsThemStyle = true; - this.logList.View = System.Windows.Forms.View.Details; - this.logList.MouseEnter += new System.EventHandler(this.logList_MouseEnter); - // // tabControl1 // this.tabControl1.Alignment = System.Windows.Forms.TabAlignment.Bottom; @@ -670,7 +653,7 @@ // // tabPage1 // - this.tabPage1.Controls.Add(this.onlineList); + this.tabPage1.Controls.Add(this.servicesOnlineList); this.tabPage1.Location = new System.Drawing.Point(4, 4); this.tabPage1.Margin = new System.Windows.Forms.Padding(4); this.tabPage1.Name = "tabPage1"; @@ -680,24 +663,6 @@ this.tabPage1.Text = "在线列表"; this.tabPage1.UseVisualStyleBackColor = true; // - // onlineList - // - this.onlineList.BorderStyle = System.Windows.Forms.BorderStyle.None; - this.onlineList.CheckBoxes = true; - this.onlineList.ContextMenuStrip = this.CmdContext; - this.onlineList.Dock = System.Windows.Forms.DockStyle.Fill; - this.onlineList.FullRowSelect = true; - this.onlineList.HideSelection = false; - this.onlineList.Location = new System.Drawing.Point(4, 4); - this.onlineList.Margin = new System.Windows.Forms.Padding(4); - this.onlineList.Name = "onlineList"; - this.onlineList.Size = new System.Drawing.Size(1091, 190); - this.onlineList.TabIndex = 0; - this.onlineList.UseCompatibleStateImageBehavior = false; - this.onlineList.UseWindowsThemStyle = false; - this.onlineList.View = System.Windows.Forms.View.Details; - this.onlineList.MouseEnter += new System.EventHandler(this.onlineList_MouseEnter); - // // statusStrip1 // this.statusStrip1.ImageScalingSize = new System.Drawing.Size(20, 20); @@ -999,6 +964,41 @@ this.toolStripMenuItem3.Text = "关于程序(&H)"; this.toolStripMenuItem3.Click += new System.EventHandler(this.About); // + // logList + // + this.logList.BorderStyle = System.Windows.Forms.BorderStyle.None; + this.logList.ContextMenuStrip = this.logsContext; + this.logList.Dock = System.Windows.Forms.DockStyle.Fill; + this.logList.FullRowSelect = true; + this.logList.HideSelection = false; + this.logList.Location = new System.Drawing.Point(4, 4); + this.logList.Margin = new System.Windows.Forms.Padding(4); + this.logList.Name = "logList"; + this.logList.Size = new System.Drawing.Size(352, 190); + this.logList.TabIndex = 0; + this.logList.UseCompatibleStateImageBehavior = false; + this.logList.UseWindowsThemStyle = true; + this.logList.View = System.Windows.Forms.View.Details; + this.logList.MouseEnter += new System.EventHandler(this.logList_MouseEnter); + // + // onlineList + // + this.servicesOnlineList.BorderStyle = System.Windows.Forms.BorderStyle.None; + this.servicesOnlineList.CheckBoxes = true; + this.servicesOnlineList.ContextMenuStrip = this.cmdContext; + this.servicesOnlineList.Dock = System.Windows.Forms.DockStyle.Fill; + this.servicesOnlineList.FullRowSelect = true; + this.servicesOnlineList.HideSelection = false; + this.servicesOnlineList.Location = new System.Drawing.Point(4, 4); + this.servicesOnlineList.Margin = new System.Windows.Forms.Padding(4); + this.servicesOnlineList.Name = "onlineList"; + this.servicesOnlineList.Size = new System.Drawing.Size(1091, 190); + this.servicesOnlineList.TabIndex = 0; + this.servicesOnlineList.UseCompatibleStateImageBehavior = false; + this.servicesOnlineList.UseWindowsThemStyle = false; + this.servicesOnlineList.View = System.Windows.Forms.View.Details; + this.servicesOnlineList.MouseEnter += new System.EventHandler(this.onlineList_MouseEnter); + // // MainApplication // this.AutoScaleDimensions = new System.Drawing.SizeF(8F, 15F); @@ -1014,7 +1014,7 @@ this.StartPosition = System.Windows.Forms.FormStartPosition.CenterScreen; this.FormClosing += new System.Windows.Forms.FormClosingEventHandler(this.MainApplication_FormClosing); this.Load += new System.EventHandler(this.MainApplication_Load); - this.CmdContext.ResumeLayout(false); + this.cmdContext.ResumeLayout(false); this.logsContext.ResumeLayout(false); this.splitContainer1.Panel1.ResumeLayout(false); this.splitContainer1.Panel2.ResumeLayout(false); @@ -1024,10 +1024,10 @@ this.panel1.PerformLayout(); ((System.ComponentModel.ISupportInitialize)(this.columntrackBar)).EndInit(); ((System.ComponentModel.ISupportInitialize)(this.rowtrackBar)).EndInit(); - this.splitContainer2.Panel1.ResumeLayout(false); - this.splitContainer2.Panel2.ResumeLayout(false); - ((System.ComponentModel.ISupportInitialize)(this.splitContainer2)).EndInit(); - this.splitContainer2.ResumeLayout(false); + this.splitContainer.Panel1.ResumeLayout(false); + this.splitContainer.Panel2.ResumeLayout(false); + ((System.ComponentModel.ISupportInitialize)(this.splitContainer)).EndInit(); + this.splitContainer.ResumeLayout(false); this.tabControl2.ResumeLayout(false); this.tabPage2.ResumeLayout(false); this.tabControl1.ResumeLayout(false); @@ -1057,7 +1057,7 @@ private System.Windows.Forms.ToolStripStatusLabel toolStripStatusLabel5; private System.Windows.Forms.ToolStripStatusLabel toolStripStatusLabel6; private System.Windows.Forms.ToolStripStatusLabel stripConnectedNum; - private System.Windows.Forms.ContextMenuStrip CmdContext; + private System.Windows.Forms.ContextMenuStrip cmdContext; private System.Windows.Forms.ToolStripMenuItem 发送信息ToolStripMenuItem; private System.Windows.Forms.ToolStripMenuItem 备注更改ToolStripMenuItem; private System.Windows.Forms.ToolStripMenuItem 会话管理ToolStripMenuItem; @@ -1091,9 +1091,9 @@ private System.Windows.Forms.Label label1; private System.Windows.Forms.LinkLabel linkLabel1; private System.Windows.Forms.Label fsd; - private System.Windows.Forms.Label row; + private System.Windows.Forms.Label viewRow; private System.Windows.Forms.TrackBar columntrackBar; - private System.Windows.Forms.Label column; + private System.Windows.Forms.Label viewColumn; private System.Windows.Forms.Button button2; private System.Windows.Forms.Button button1; private System.Windows.Forms.ToolStrip toolStrip1; @@ -1117,11 +1117,11 @@ private System.Windows.Forms.ToolStripMenuItem toolStripMenuItem11; private System.Windows.Forms.ToolStripSeparator toolStripSeparator7; private System.Windows.Forms.ToolStripMenuItem 桌面记录查看ToolStripMenuItem; - private System.Windows.Forms.SplitContainer splitContainer2; + private System.Windows.Forms.SplitContainer splitContainer; private System.Windows.Forms.TabControl tabControl2; private System.Windows.Forms.TabPage tabPage2; private System.Windows.Forms.TabPage tabPage1; - private UserControls.UListView onlineList; + private UserControls.UListView servicesOnlineList; private System.Windows.Forms.ToolStripMenuItem toolStripMenuItem2; private System.Windows.Forms.ToolStripMenuItem toolStripMenuItem7; private System.Windows.Forms.ComboBox groupBox; diff --git a/SiMay.RemoteMonitor/MainApplication/MainApplication.cs b/SiMay.RemoteMonitor/MainApplication/MainApplication.cs index 85b8658..f444217 100644 --- a/SiMay.RemoteMonitor/MainApplication/MainApplication.cs +++ b/SiMay.RemoteMonitor/MainApplication/MainApplication.cs @@ -32,14 +32,11 @@ namespace SiMay.RemoteMonitor.MainApplication private bool _isRun = true; private int _connect_count = 0; - //private int _desktopViewHeight = 150; - //private int _desktopViewWidth = 250; - //private int _deskrefreshTimeSpan = 1500; private long _sendTransferredBytes = 0; private long _receiveTransferredBytes = 0; private const string GROUP_ALL = "全部"; - private System.Timers.Timer _timer; + private System.Timers.Timer _flowCalcTimer; private System.Timers.Timer _viewCarouselTimer; private DesktopViewSettingContext _viewCarouselContext = new DesktopViewSettingContext(); private Color _closeScreenColor = Color.FromArgb(127, 175, 219); @@ -48,6 +45,7 @@ namespace SiMay.RemoteMonitor.MainApplication private AppMainAdapterHandler _appMainAdapterHandler = new AppMainAdapterHandler(); private void MainApplication_Load(object sender, EventArgs e) { + this.ViewOnAdaptiveHandler(); this.OnLoadConfiguration(); this.RegisterMessageHandler(); } @@ -71,14 +69,14 @@ namespace SiMay.RemoteMonitor.MainApplication this._imgList.Images.Add("error", Resources.erro); //计算实时上下传输流量 - this._timer = new System.Timers.Timer(); - this._timer.Interval = 1000; - this._timer.Elapsed += (a, b) => + this._flowCalcTimer = new System.Timers.Timer(); + this._flowCalcTimer.Interval = 1000; + this._flowCalcTimer.Elapsed += (a, b) => { if (!_isRun) { - _timer.Stop(); - _timer.Dispose(); + _flowCalcTimer.Stop(); + _flowCalcTimer.Dispose(); return; } @@ -92,30 +90,28 @@ namespace SiMay.RemoteMonitor.MainApplication })); }; - this._timer.Start(); + this._flowCalcTimer.Start(); if (AppConfiguration.SessionMode == "1") { this.stripHost.Text = AppConfiguration.ServiceIPAddress; - this.stripPort.Text = AppConfiguration.ServicePort; + this.stripPort.Text = AppConfiguration.ServicePort.ToString(); } else { this.stripHost.Text = AppConfiguration.IPAddress; - this.stripPort.Text = AppConfiguration.Port; + this.stripPort.Text = AppConfiguration.Port.ToString(); } this.rowtrackBar.Value = this._viewCarouselContext.ViewRow; this.columntrackBar.Value = this._viewCarouselContext.ViewColum; - this.row.Text = columntrackBar.Value.ToString(); - this.column.Text = rowtrackBar.Value.ToString(); - this.splitContainer2.SplitterDistance = (splitContainer2.Width / 4); + this.viewRow.Text = columntrackBar.Value.ToString(); + this.viewColumn.Text = rowtrackBar.Value.ToString(); + this.splitContainer.SplitterDistance = (splitContainer.Width / 4); this.logList.SmallImageList = _imgList; this.logList.Columns.Add("发生时间", 150); this.logList.Columns.Add("发生事件", 1000); - this.onlineList.ListViewItemSorter = new Entitys.Common.ListViewColumnSorter(); - //this.onlineList.ColumnClick += new ColumnClickEventHandler(Entitys.Common.ListViewHelper.ListView_ColumnClick); this.groupBox.Text = GROUP_ALL; string[] columnsTitle = new string[] { @@ -136,7 +132,7 @@ namespace SiMay.RemoteMonitor.MainApplication }; for (int i = 0; i < columnsTitle.Length; i++) - this.onlineList.Columns.Insert(i, columnsTitle[i], 150); + this.servicesOnlineList.Columns.Insert(i, columnsTitle[i], 150); var apps = SysUtil.ApplicationTypes.OrderByDescending(x => x.Rank).ToList(); apps.ForEach(c => @@ -144,7 +140,7 @@ namespace SiMay.RemoteMonitor.MainApplication var type = c.Type; var stripMenu = new UToolStripMenuItem(type.GetApplicationName(), c.Type); stripMenu.Click += StripMenu_Click; - this.CmdContext.Items.Insert(0, stripMenu); + this.cmdContext.Items.Insert(0, stripMenu); if (c.Type.OnTools()) { @@ -169,29 +165,45 @@ namespace SiMay.RemoteMonitor.MainApplication } private void desktopViewLayout_Resize(object sender, EventArgs e) { - ViewOnResize(); + this.ViewOnAdaptiveHandler(); } - private void ViewOnResize() + private void desktopViewLayout_Scroll(object sender, ScrollEventArgs e) { + this.ViewOnAdaptiveHandler(); + } + private void ViewOnAdaptiveHandler() + { + var viewCount = _viewCarouselContext.ViewColum * _viewCarouselContext.ViewRow; + var containerRectangle = this.desktopViewLayout.DisplayRectangle; + var marginalRight = (_viewCarouselContext.ViewColum * 9) / this._viewCarouselContext.ViewColum; + var width = (this.desktopViewLayout.Width / _viewCarouselContext.ViewColum) - marginalRight; + var height = (this.desktopViewLayout.Height / _viewCarouselContext.ViewRow) - marginalRight; + + this._viewCarouselContext.ViewWidth = width; + this._viewCarouselContext.ViewHeight = height; + if (this.desktopViewLayout.Controls.Count <= 0) return; - var viewCount = _viewCarouselContext.ViewColum * _viewCarouselContext.ViewRow; + var displayTop = Math.Abs(containerRectangle.Y);//容器的可视top(y偏差纠正) + var displayBottom = Math.Abs(displayTop + desktopViewLayout.Height);//容器的可视bottom - var marginalRight = (_viewCarouselContext.ViewColum * 9) / this._viewCarouselContext.ViewColum; - var width = (this.desktopViewLayout.ClientRectangle.Width / _viewCarouselContext.ViewColum) - marginalRight; - var height = (this.desktopViewLayout.ClientRectangle.Height / _viewCarouselContext.ViewRow) - marginalRight; + var startControlIndex = (displayTop / height) * this._viewCarouselContext.ViewColum; + var endControlIndex = (displayBottom / height) * this._viewCarouselContext.ViewColum; + + //Console.WriteLine(containerRectangle.Top + "|" + containerRectangle.Bottom); + //Console.WriteLine($"{startControlIndex} | {endControlIndex}"); int index = 0; - foreach (IDesktopView view in this.desktopViewLayout.Controls) + foreach (var view in desktopViewLayout.Controls.Cast()) { - var containerRectangle = this.desktopViewLayout.ClientRectangle; - if (view is Control control) { - var controlRectangle = new Rectangle(control.Left, control.Top, control.Width, control.Height); - view.InVisbleArea = this.WhetherContainsInClientRectangle(containerRectangle, controlRectangle); - Console.WriteLine(view.InVisbleArea + " " + index); + var viewX = Math.Abs(control.Location.X); + var viewY = Math.Abs(control.Location.Y); + var controlRectangle = new Rectangle(viewX, viewY, control.Width, control.Height); + view.InVisbleArea = RectangleHelper.WhetherContainsInDisplayRectangle(new Rectangle(0, displayTop, this.desktopViewLayout.Width, this.desktopViewLayout.Height), controlRectangle); + Console.WriteLine($"{startControlIndex} | {endControlIndex} - " + view.InVisbleArea + " " + index); } if (view.Width == width && view.Height == height && index++ == viewCount) continue; @@ -204,11 +216,6 @@ namespace SiMay.RemoteMonitor.MainApplication } } - public bool WhetherContainsInClientRectangle(Rectangle containerRect, Rectangle childrect) - { - return childrect.Y + childrect.Height >= containerRect.Y && childrect.Y <= containerRect.Bottom; - } - private void ViewCarouselFunc(object sender, System.Timers.ElapsedEventArgs e) { var viewCount = _viewCarouselContext.ViewColum * _viewCarouselContext.ViewRow; @@ -222,7 +229,7 @@ namespace SiMay.RemoteMonitor.MainApplication }); } - this.ViewOnResize(); + this.ViewOnAdaptiveHandler(); } private void InvokeUI(Action action) => this.Invoke(new Action(action)); @@ -282,14 +289,14 @@ namespace SiMay.RemoteMonitor.MainApplication var groupName = syncContext.KeyDictions[SysConstants.GroupName].ConvertTo(); if (!groupBox.Items.Contains(groupName)) - groupBox.Items.Add(groupName); + this.groupBox.Items.Add(groupName); //分组 if (groupBox.Text == groupName || groupBox.Text == GROUP_ALL) - this.onlineList.Items.Add(listItem); + this.servicesOnlineList.Items.Add(listItem); - _connect_count++; - stripConnectedNum.Text = _connect_count.ToString(); + this._connect_count++; + this.stripConnectedNum.Text = _connect_count.ToString(); Win32Api.FlashWindow(this.Handle, true); //上线任务栏图标闪烁 } @@ -307,7 +314,11 @@ namespace SiMay.RemoteMonitor.MainApplication private IDesktopView OnCreateDesktopViewHandlerEvent(SessionSyncContext syncContext) { - var view = new UDesktopView(syncContext); + var view = new UDesktopView(syncContext) + { + Height = this._viewCarouselContext.ViewHeight, + Width = this._viewCarouselContext.ViewWidth + }; view.OnDoubleClickEvent += DesktopViewDbClick; this.desktopViewLayout.Controls.Add(view); @@ -378,13 +389,13 @@ namespace SiMay.RemoteMonitor.MainApplication /// private IEnumerable GetSelectedListItem() { - if (onlineList.SelectedItems.Count != 0) + if (servicesOnlineList.SelectedItems.Count != 0) { - var SelectItem = onlineList.SelectedItems; + var SelectItem = servicesOnlineList.SelectedItems; for (int i = 0; i < SelectItem.Count; i++) - onlineList.Items[SelectItem[i].Index].Checked = true; + servicesOnlineList.Items[SelectItem[i].Index].Checked = true; - foreach (USessionListItem item in onlineList.Items) + foreach (USessionListItem item in servicesOnlineList.Items) { if (item.Checked) { @@ -475,10 +486,10 @@ namespace SiMay.RemoteMonitor.MainApplication private void CmdContext_Opening(object sender, CancelEventArgs e) { - if (onlineList.SelectedItems.Count == 0) - CmdContext.Enabled = false; + if (servicesOnlineList.SelectedItems.Count == 0) + cmdContext.Enabled = false; else - CmdContext.Enabled = true; + cmdContext.Enabled = true; } private void CreateService(object sender, EventArgs e) @@ -588,13 +599,13 @@ namespace SiMay.RemoteMonitor.MainApplication private void OnlineList_OnSelected(object sender, EventArgs e) { - foreach (ListViewItem item in onlineList.Items) + foreach (ListViewItem item in servicesOnlineList.Items) item.Checked = true; } private void OnileList_OnUnSelected(object sender, EventArgs e) { - foreach (ListViewItem item in onlineList.Items) + foreach (ListViewItem item in servicesOnlineList.Items) item.Checked = false; } @@ -699,19 +710,19 @@ namespace SiMay.RemoteMonitor.MainApplication this._viewCarouselContext.ViewRow = rowtrackBar.Value; this._viewCarouselContext.ViewColum = columntrackBar.Value; - this.ViewOnResize(); + this.ViewOnAdaptiveHandler(); this.WriteRuninglog("设置已保存!", "ok"); } private void RowtrackBar_Scroll(object sender, EventArgs e) { - this.row.Text = columntrackBar.Value.ToString(); + this.viewRow.Text = columntrackBar.Value.ToString(); } private void ColumntrackBar_Scroll(object sender, EventArgs e) { - this.column.Text = rowtrackBar.Value.ToString(); + this.viewColumn.Text = rowtrackBar.Value.ToString(); } private void button1_Click(object sender, EventArgs e) @@ -856,12 +867,12 @@ namespace SiMay.RemoteMonitor.MainApplication private void logList_MouseEnter(object sender, EventArgs e) { - this.splitContainer2.SplitterDistance = splitContainer2.Width - (splitContainer2.Width / 4); + this.splitContainer.SplitterDistance = splitContainer.Width - (splitContainer.Width / 4); } private void onlineList_MouseEnter(object sender, EventArgs e) { - this.splitContainer2.SplitterDistance = (splitContainer2.Width / 4); + this.splitContainer.SplitterDistance = (splitContainer.Width / 4); } private void ToolStripMenuItem7_Click(object sender, EventArgs e) @@ -888,7 +899,7 @@ namespace SiMay.RemoteMonitor.MainApplication foreach (var item in this._appMainAdapterHandler.SyncContexts) { if (item.KeyDictions[SysConstants.GroupName].ConvertTo() == groupBox.Text || groupBox.Text == GROUP_ALL) - this.onlineList.Items.Add(item.KeyDictions[SysConstantsExtend.SessionListItem].ConvertTo()); + this.servicesOnlineList.Items.Add(item.KeyDictions[SysConstantsExtend.SessionListItem].ConvertTo()); } } @@ -951,7 +962,7 @@ namespace SiMay.RemoteMonitor.MainApplication this._viewCarouselTimer.Interval = _viewCarouselContext.ViewCarouselInterval; this._viewCarouselTimer.Start(); } - this.ViewOnResize(); + this.ViewOnAdaptiveHandler(); } } } diff --git a/SiMay.RemoteMonitor/UserControls/UDesktopView.cs b/SiMay.RemoteMonitor/UserControls/UDesktopView.cs index f973caf..168a439 100644 --- a/SiMay.RemoteMonitor/UserControls/UDesktopView.cs +++ b/SiMay.RemoteMonitor/UserControls/UDesktopView.cs @@ -17,6 +17,7 @@ namespace SiMay.RemoteMonitor.UserControls public UDesktopView(SessionSyncContext syncContext) { SessionSyncContext = syncContext; + InitializeComponent(); } diff --git a/SiMay.RemoteMonitor/UserControls/UListView.cs b/SiMay.RemoteMonitor/UserControls/UListView.cs index b9e8286..39861d6 100644 --- a/SiMay.RemoteMonitor/UserControls/UListView.cs +++ b/SiMay.RemoteMonitor/UserControls/UListView.cs @@ -1,5 +1,5 @@ using SiMay.Core.Common; -using SiMay.RemoteMonitor.Entitys.Common; +using SiMay.RemoteMonitor.Entitys; using System; using System.Collections.Generic; using System.Linq; @@ -19,12 +19,11 @@ namespace SiMay.RemoteMonitor.UserControls private const short UISF_HIDEFOCUS = 0x1; private readonly IntPtr _removeDots = new IntPtr((int)UIS_SET << 16 | (int)(short)UISF_HIDEFOCUS); - private ListViewColumnSorter LvwColumnSorter { get; set; } + private ListViewColumnSorter _sorter = new ListViewColumnSorter(); public UListView() { SetStyle(ControlStyles.OptimizedDoubleBuffer | ControlStyles.AllPaintingInWmPaint, true); - this.LvwColumnSorter = new ListViewColumnSorter(); - this.ListViewItemSorter = LvwColumnSorter; + this.ListViewItemSorter = _sorter; this.View = View.Details; this.FullRowSelect = true; } @@ -34,23 +33,23 @@ namespace SiMay.RemoteMonitor.UserControls base.OnColumnClick(e); // Determine if clicked column is already the column that is being sorted. - if (e.Column == this.LvwColumnSorter.SortColumn) + if (e.Column == this._sorter.SortColumn) { // Reverse the current sort direction for this column. - this.LvwColumnSorter.Order = (this.LvwColumnSorter.Order == SortOrder.Ascending) + this._sorter.Order = (this._sorter.Order == SortOrder.Ascending) ? SortOrder.Descending : SortOrder.Ascending; } else { // Set the column number that is to be sorted; default to ascending. - this.LvwColumnSorter.SortColumn = e.Column; - this.LvwColumnSorter.Order = SortOrder.Ascending; + this._sorter.SortColumn = e.Column; + this._sorter.Order = SortOrder.Ascending; } // Perform the sort with these new sort options. - //if (!this.VirtualMode) - this.Sort(); + if (!this.VirtualMode) + this.Sort(); } protected override void OnHandleCreated(EventArgs e) diff --git a/SiMayRemoteManager.sln b/SiMayRemoteManager.sln index 9e3c09d..d70ffc2 100644 --- a/SiMayRemoteManager.sln +++ b/SiMayRemoteManager.sln @@ -11,8 +11,6 @@ Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "SiMay.Daemon", "SiMay.Daemo EndProject Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "SiMay.UpdateClient", "SiMay.UpdateClient\SiMay.UpdateClient.csproj", "{76E07A4F-8839-4260-925A-3179DB1C6045}" EndProject -Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "SiMay.Sockets", "SiMay.Sockets\SiMay.Sockets.csproj", "{B0F8473C-10B8-4CF7-AE18-32037FA9BBAE}" -EndProject Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "SiMay.ServiceCore", "SiMay.RemoteClient.NewCore\SiMay.ServiceCore.csproj", "{8D061D46-9E59-42B0-91DC-4E380E4AE0BA}" EndProject Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "SiMay.Sockets.V4", "SiMay.Sockets.V4\SiMay.Sockets.V4.csproj", "{D181FCCE-ECC7-4710-89CC-D97F94A6181B}" @@ -104,18 +102,6 @@ Global {76E07A4F-8839-4260-925A-3179DB1C6045}.Release|x64.Build.0 = Release|Any CPU {76E07A4F-8839-4260-925A-3179DB1C6045}.Release|x86.ActiveCfg = Release|Any CPU {76E07A4F-8839-4260-925A-3179DB1C6045}.Release|x86.Build.0 = Release|Any CPU - {B0F8473C-10B8-4CF7-AE18-32037FA9BBAE}.Debug|Any CPU.ActiveCfg = Debug|Any CPU - {B0F8473C-10B8-4CF7-AE18-32037FA9BBAE}.Debug|Any CPU.Build.0 = Debug|Any CPU - {B0F8473C-10B8-4CF7-AE18-32037FA9BBAE}.Debug|x64.ActiveCfg = Debug|Any CPU - {B0F8473C-10B8-4CF7-AE18-32037FA9BBAE}.Debug|x64.Build.0 = Debug|Any CPU - {B0F8473C-10B8-4CF7-AE18-32037FA9BBAE}.Debug|x86.ActiveCfg = Debug|Any CPU - {B0F8473C-10B8-4CF7-AE18-32037FA9BBAE}.Debug|x86.Build.0 = Debug|Any CPU - {B0F8473C-10B8-4CF7-AE18-32037FA9BBAE}.Release|Any CPU.ActiveCfg = Release|Any CPU - {B0F8473C-10B8-4CF7-AE18-32037FA9BBAE}.Release|Any CPU.Build.0 = Release|Any CPU - {B0F8473C-10B8-4CF7-AE18-32037FA9BBAE}.Release|x64.ActiveCfg = Release|Any CPU - {B0F8473C-10B8-4CF7-AE18-32037FA9BBAE}.Release|x64.Build.0 = Release|Any CPU - {B0F8473C-10B8-4CF7-AE18-32037FA9BBAE}.Release|x86.ActiveCfg = Release|Any CPU - {B0F8473C-10B8-4CF7-AE18-32037FA9BBAE}.Release|x86.Build.0 = Release|Any CPU {8D061D46-9E59-42B0-91DC-4E380E4AE0BA}.Debug|Any CPU.ActiveCfg = Debug|Any CPU {8D061D46-9E59-42B0-91DC-4E380E4AE0BA}.Debug|Any CPU.Build.0 = Debug|Any CPU {8D061D46-9E59-42B0-91DC-4E380E4AE0BA}.Debug|x64.ActiveCfg = Debug|x64 @@ -245,7 +231,6 @@ Global {1AADC6F7-6FF9-4C68-8A26-E507F22B9060} = {5E72F9F6-8DB0-4727-92F3-D05A3CC0348E} {77867DE2-193E-4533-B365-31CEF16A876B} = {FBA5D1FE-11EA-4FAE-B88F-7E2E809419C9} {76E07A4F-8839-4260-925A-3179DB1C6045} = {FBA5D1FE-11EA-4FAE-B88F-7E2E809419C9} - {B0F8473C-10B8-4CF7-AE18-32037FA9BBAE} = {D0952F11-B4B6-4AD4-8F72-C35BD6A33D59} {8D061D46-9E59-42B0-91DC-4E380E4AE0BA} = {FBA5D1FE-11EA-4FAE-B88F-7E2E809419C9} {D181FCCE-ECC7-4710-89CC-D97F94A6181B} = {D0952F11-B4B6-4AD4-8F72-C35BD6A33D59} {BF5B6F41-D688-447F-BF81-EA821216F188} = {9328FEED-6E95-4863-BB7B-521D0D02D7FA} -- Gitee From bd354cf6cfa6bcfb60b66ef19c3d3d524a4b30d0 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E6=96=87=E7=8E=8B=E7=8E=8B?= <596461462@qq.com> Date: Sun, 2 Feb 2020 23:30:10 +0800 Subject: [PATCH 05/19] =?UTF-8?q?6.0.0.1=EF=BC=8C=E4=BB=A3=E7=A0=81?= =?UTF-8?q?=E9=87=8D=E6=9E=84=EF=BC=8C=E9=80=9A=E8=AE=AF=E5=8D=8F=E8=AE=AE?= =?UTF-8?q?=E5=8D=87=E7=BA=A7=EF=BC=8C=E4=B8=AD=E9=97=B4=E6=9C=8D=E5=8A=A1?= =?UTF-8?q?=E9=87=8D=E6=9E=84(=E6=9C=AA=E5=AE=8C=E6=88=90)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- README.md | 5 +- .../{CompressHelper.cs => GZipHelper.cs} | 2 +- SiMay.Basic/ImageHelper.cs | 36 -- SiMay.Basic/ObjectHelper.cs | 5 + SiMay.Basic/SiMay.Basic.csproj | 8 +- .../ByteConverterHelper.cs} | 2 +- SiMay.Core/{ => Common}/FileIconUtil.cs | 1 + SiMay.Core/Common/RegValueHelper.cs | 8 +- SiMay.Core/Common/RegistryKeyHelper.cs | 8 +- .../Extensions/RegistryKeyExtensions.cs | 8 +- SiMay.Core/MessageHead.cs | 271 +++++++-------- SiMay.Core/MessageHelper.cs | 15 +- SiMay.Core/Packets/AckPack.cs | 7 +- ...ialogPack.cs => ActivedApplicationPack.cs} | 9 +- .../Packets/Audio/AudioDeviceStatesPack.cs | 5 +- SiMay.Core/Packets/Audio/AudioOptionsPack.cs | 5 +- .../Packets/DesktopRecordGetFramePack.cs | 5 +- SiMay.Core/Packets/DesktopViewDescribePack.cs | 5 +- SiMay.Core/Packets/DesktopViewGetFramePack.cs | 7 +- .../Packets/FileManager/FileCopyPack.cs | 7 +- .../FileManager/FileCreateDirectoryPack.cs | 7 +- .../Packets/FileManager/FileDeletePack.cs | 7 +- .../FileManager/FileDirectoryGetFilesPack.cs | 9 +- .../Packets/FileManager/FileDownloadPack.cs | 9 +- .../Packets/FileManager/FileExceptionPack.cs | 5 +- .../Packets/FileManager/FileExcutePack.cs | 5 +- .../FileManager/FileGetTreeDirectoryPack.cs | 7 +- .../Packets/FileManager/FileListItemsPack.cs | 7 +- .../Packets/FileManager/FileReNamePack.cs | 7 +- .../FileManager/FileRedirectionPath.cs | 5 +- .../Packets/FileManager/FileTextPack.cs | 7 +- .../Packets/FileManager/FileUploadPack.cs | 11 +- SiMay.Core/Packets/LoginPack.cs | 5 +- SiMay.Core/Packets/MessagePack.cs | 3 +- SiMay.Core/Packets/Reg/RegDeleteSubKeyPack.cs | 5 +- SiMay.Core/Packets/Reg/RegDeleteValuePack.cs | 5 +- SiMay.Core/Packets/Reg/RegNewSubkeyPack.cs | 5 +- SiMay.Core/Packets/Reg/RegNewValuePack.cs | 5 +- SiMay.Core/Packets/Reg/RegOpenSubKeyPack.cs | 5 +- SiMay.Core/Packets/Reg/RegOperFinshPack.cs | 5 +- .../Packets/Reg/RegRootDirectorysPack.cs | 5 +- SiMay.Core/Packets/Reg/RegSubKeyValuePack.cs | 5 +- SiMay.Core/Packets/Reg/RegValueItem.cs | 5 +- SiMay.Core/Packets/Reg/RegValuesPack.cs | 5 +- .../RegEdit/DoChangeRegistryValuePack.cs | 5 +- .../RegEdit/DoCreateRegistryKeyPack.cs | 5 +- .../RegEdit/DoCreateRegistryValuePack.cs | 3 +- .../RegEdit/DoDeleteRegistryKeyPack.cs | 5 +- .../RegEdit/DoDeleteRegistryValuePack.cs | 5 +- .../Packets/RegEdit/DoLoadRegistryKeyPack.cs | 5 +- .../RegEdit/DoRenameRegistryKeyPack.cs | 5 +- .../RegEdit/DoRenameRegistryValuePack.cs | 5 +- .../GetChangeRegistryValueResponsePack.cs | 5 +- .../GetCreateRegistryKeyResponsePack.cs | 5 +- .../GetCreateRegistryValueResponsePack.cs | 5 +- .../GetDeleteRegistryKeyResponsePack.cs | 5 +- .../GetDeleteRegistryValueResponsePack.cs | 5 +- .../RegEdit/GetRegistryKeysResponsePack.cs | 5 +- .../GetRenameRegistryKeyResponsePack.cs | 5 +- .../GetRenameRegistryValueResponsePack.cs | 5 +- SiMay.Core/Packets/RegEdit/RegSeekerMatch.cs | 5 +- SiMay.Core/Packets/RegEdit/RegValueData.cs | 3 +- SiMay.Core/Packets/RemoteUpdatePack.cs | 3 +- .../Packets/Screen/MonitorChangePack.cs | 5 +- .../Packets/Screen/ScreenBitInfoPack.cs | 7 +- .../Packets/Screen/ScreenClipoardValuePack.cs | 5 +- .../Packets/Screen/ScreenFragmentPack.cs | 3 +- .../Packets/Screen/ScreenHotRectanglePack.cs | 5 +- .../{ScreenMKeyPack.cs => ScreenKeyPack.cs} | 3 +- .../Packets/Screen/ScreenSetClipoardPack.cs | 5 +- SiMay.Core/Packets/Screen/ScreenSetQtyPack.cs | 5 +- SiMay.Core/Packets/ServicePluginPack.cs | 7 +- SiMay.Core/Packets/Startup/StartupItemPack.cs | 5 +- .../Startup/StartupOperResponsePack.cs | 3 +- SiMay.Core/Packets/SysManager/ProcessInfo.cs | 5 +- .../Packets/SysManager/SessionManagerPack.cs | 9 +- SiMay.Core/Packets/SysManager/SysKillPack.cs | 5 +- .../Packets/SysManager/SysWindowMaxPack.cs | 5 +- .../Packets/SysManager/SystemInfoPack.cs | 11 +- .../TcpConnection/TcpConnectionItem.cs | 3 +- .../TcpConnection/TcpConnectionPack.cs | 9 +- SiMay.Core/SiMay.Core.csproj | 17 +- SiMay.Daemon/Program.cs | 45 --- .../HttpRemoteMonitorService.cs | 44 +-- .../SiMay.Net.SessionProvider.Core.csproj | 10 +- ...{SendMessageHelper.cs => MessageHelper.cs} | 9 +- .../TcpProxySessionProviderHandle.cs | 156 +++++---- .../TcpSocketSessionProviderHandle.cs | 11 +- ...ionHandle.cs => SessionProviderContext.cs} | 34 +- .../SessionBased/TcpProxySessionBased.cs | 18 +- .../SessionBased/TcpSocketSessionBased.cs | 8 +- SiMay.Net.SessionProvider/SessionProvider.cs | 4 +- .../SessionProviderFactory.cs | 4 +- .../SessionProviderOptions.cs | 14 +- .../SiMay.Net.SessionProvider.csproj | 22 +- .../ChannelListViewItem.cs | 4 +- .../Packet/AckPacket.cs | 24 -- .../Packet/PackDeserializeSetup.cs | 182 ---------- .../Packet/PackSerializeSetup.cs | 164 --------- .../Packet/PacketBuilderHelper.cs | 24 -- .../SessionProviderService.cs | 80 ++--- .../SiMay.Net.SessionProviderService.csproj | 13 +- .../SysContact.cs | 12 +- ...Context.cs => TcpSessionChannelContext.cs} | 128 ++++--- SiMay.RemoteClient.NewCore/App.config | 2 +- .../AppConfiguartion.cs | 94 +++-- .../ApplicationService/AForgeViedo.cs | 6 +- .../ApplicationService/AudioService.cs | 21 +- .../ApplicationService/FileService.cs | 81 +++-- .../ApplicationService/Keyboard.cs | 2 +- .../ApplicationService/KeyboardService.cs | 18 +- .../ApplicationService/ProcessSpy.cs | 50 --- .../Registry/RegistryEditor.cs | 2 +- .../Registry/RegistrySeeker.cs | 2 +- .../RegistryEditorService.cs | 51 +-- .../ApplicationService/ScreenService.cs | 49 ++- .../ApplicationService/ServiceManagerBase.cs | 139 -------- .../ApplicationService/ShellService.cs | 16 +- .../ApplicationService/StartupService.cs | 81 +++-- .../ApplicationService/SystemService.cs | 30 +- .../TcpConnectionService.cs | 31 +- .../ApplicationService/VideoService.cs | 23 +- .../Helper/ImageExtensionHelper.cs | 5 +- .../Helper}/RegValueHelper.cs | 0 .../MainService/MainService.cs | 283 +++++++-------- .../MainService/ManagerTaskQueue.cs | 34 -- .../{UpdateService.cs => ServiceTaskQueue.cs} | 11 +- ...essionHelper.cs => SystemSessionHelper.cs} | 8 +- SiMay.RemoteClient.NewCore/Program.cs | 6 +- .../Properties/Resources.Designer.cs | 2 +- .../Properties/Settings.Designer.cs | 2 +- .../ServiceBase/ApplicationProtocolService.cs | 97 ++++++ .../ServiceBase/ApplicationRemoteService.cs | 61 ++++ .../ServiceBase/ApplicationServiceBase.cs | 35 ++ .../ServiceBase/MainApplicationService.cs | 8 +- .../SiMay.ServiceCore.csproj | 31 +- SiMay.RemoteClient.NewCore/SysUtil.cs | 30 +- SiMay.RemoteClient.NewCore/packages.config | 4 +- .../ApplicationAdapterHandler.cs} | 92 ++--- .../ApplicationProtocolAdapterHandler.cs | 110 ++++++ .../MainApplicationAdapterHandler.cs | 94 +++++ SiMay.RemoteControlsCore/AppConfiguration.cs | 36 +- .../AudioAdapterHandler.cs | 27 +- .../FileCommon/AwaitAutoResetEvent.cs | 0 .../KeyboardAdapterHandler.cs | 16 +- .../RegistryEditorAdapterHandler.cs | 50 +-- .../RemoteFileAdapterHandler.cs | 123 ++++--- .../RemoteScreenAdapterHandler.cs | 58 +-- .../ShellAdapterHandler.cs | 8 +- .../StartupAdapterHandler.cs | 30 +- .../SystemAdapterHandler.cs | 32 +- .../TcpConnectionAdapterHandler.cs | 17 +- .../VideoAppAdapterHandler.cs | 14 +- .../Attributes/Application.cs | 4 +- .../Entitys/SessionSyncContext.cs | 4 +- .../Entitys/SuspendTaskContext.cs | 2 +- .../Extension/AppTypeExtension.cs | 4 +- .../Helper/ServiceCOMHelper.cs | 68 ---- .../Interface/IApplication.cs | 4 +- .../Interface/IFileStream.cs | 2 +- ...er.cs => MainApplicationAdapterHandler.cs} | 285 +++++++++------ SiMay.RemoteControlsCore/ResetPool.cs | 99 ------ .../SiMay.RemoteControlsCore.csproj | 32 +- SiMay.RemoteControlsCore/SysUtil.cs | 2 +- SiMay.RemoteMonitor/App.config | 2 +- .../Application/AudioApplication.Designer.cs | 6 +- .../Application/AudioApplication.cs | 12 +- .../Application/AudioConfigurationForm.cs | 12 +- .../Application/FileApplication.cs | 11 +- .../FileCommon/WindowsForFileStream.cs | 2 +- .../Application/KeyboardApplication.cs | 6 +- .../Application/RegEditorApplication.cs | 6 +- .../RegValueEditMultiStringForm.cs | 4 +- .../Application/RegValueEditStringForm.cs | 4 +- .../Application/RegValueEditWordForm.cs | 8 +- .../Application/ScreenApplication.cs | 9 +- .../Application/ShellApplication.cs | 6 +- .../Application/StartupApplication.cs | 6 +- .../Application/SystemApplication.cs | 6 +- .../Application/TcpConnectionApplication.cs | 11 +- .../Application/VideoApplication.cs | 6 +- .../MainApplication/AppSettingForm.cs | 4 +- .../BuilderServiceForm.Designer.cs | 140 +++----- .../DesktopRecordViewerForm.Designer.cs | 28 +- .../DesktopViewWallSettingForm.Designer.cs | 40 +-- .../MainApplication/LockWindowsForm.cs | 2 +- .../MainApplication.Designer.cs | 329 ++++++++---------- .../MainApplication/MainApplication.cs | 92 ++--- .../MainApplication/MainApplication.resx | 12 +- .../Properties/AssemblyInfo.cs | 4 +- .../Properties/Settings.Designer.cs | 2 +- .../SiMay.RemoteMonitor.csproj | 2 +- .../UserControls/UDesktopView.cs | 2 +- .../AppConfiguartion.cs | 2 +- .../CommonHelper.cs | 2 +- .../Entitys/StartParameter.cs | 2 +- .../FodyWeavers.xml | 0 .../Interface/IAppMainService.cs | 2 +- .../MessageHelper.cs | 2 +- .../Program.cs | 6 +- .../Properties/AssemblyInfo.cs | 4 +- .../Properties/app.manifest | 0 .../RegValueHelper.cs | 2 +- .../SiMay.RemoteService.Loader.csproj | 16 +- .../SystemInforUtil.cs | 2 +- .../app.config | 2 +- .../packages.config | 4 +- SiMay.Serialize/PacketDeserializeSetup.cs | 75 ++-- SiMay.Serialize/PacketSerializeHelper.cs | 3 +- SiMay.Serialize/PacketSerializeSetup.cs | 39 ++- .../DynamicMethodMemberAccessor.cs | 37 +- .../ReflectCachePool/EntitySerializerBase.cs | 4 +- .../IMemberAccessor.cs | 6 +- SiMay.Serialize/SiMay.Serialize.csproj | 10 +- SiMay.Serialize/SiMaySerialize.sln | 6 + .../SiMaySerializeTestApp/Program.cs | 8 +- .../Delegate/NotifyCompleteEventHandler.cs | 0 .../SiMay.Sockets.Standard.csproj | 13 + .../Tcp/Awaitable/SaeaAwaiter.cs | 5 + .../Tcp/Awaitable/SaeaExHelper.cs | 15 +- .../Tcp/Client/TcpSocketSaeaClientAgent.cs | 76 ++-- .../Tcp/Pooling/ObjectPool.cs | 0 .../Tcp/Pooling/SaeaAwaiterPool.cs | 0 .../Tcp/Pooling/SessionPool.cs | 0 .../Tcp/Server/TcpSocketSaeaServer.cs | 75 ++-- .../Tcp/Session/TcpSocketSaeaFullBased.cs | 101 +++--- .../Tcp/Session/TcpSocketSaeaPackBased.cs | 173 ++++----- .../Tcp/Session/TcpSocketSaeaSession.cs | 53 ++- .../ITcpSocketSaeaConfiguration.cs | 0 .../TcpSocketConfigurationBase.cs | 2 +- .../TcpSocketSaeaClientConfiguration.cs | 0 .../TcpSocketSaeaServerConfiguration.cs | 0 .../Tcp/TcpSocketCompletionNotify.cs | 0 .../Tcp/TcpSocketConnectionState.cs | 0 .../Tcp/TcpSocketSaeaEngineBased.cs | 102 ++++-- .../Tcp/TcpSocketSaeaSessionType.cs | 0 .../Tcp/TcpSocketsFactory.cs | 4 +- .../UtilityHelper/DeCompressHelper.cs | 6 +- .../UtilityHelper/LogHelper.cs | 31 +- SiMay.Sockets.V4/README.md | 0 SiMay.Sockets.V4/SiMay.Socket.sln | 31 -- SiMay.Sockets.V4/SiMay.Sockets.V4.csproj | 71 ---- SiMay.Sockets.V4/Tcp/Awaitable/SaeaAwaiter.cs | 53 --- .../Tcp/Awaitable/SaeaExHelper.cs | 47 --- .../Tcp/Client/TcpSocketSaeaClientAgent.cs | 138 -------- SiMay.Sockets.V4/Tcp/Pooling/ObjectPool.cs | 83 ----- .../Tcp/Server/TcpSocketSaeaServer.cs | 153 -------- .../TcpSocketConfigurationBase.cs | 38 -- .../Tcp/TcpSocketSaeaEngineBased.cs | 80 ----- SiMay.Sockets.V4/Tcp/TcpSocketsFactory.cs | 34 -- .../UtilityHelper/CompressHelper.cs | 59 ---- SiMay.Sockets.V4/UtilityHelper/LogHelper.cs | 60 ---- SiMay.Sockets.V4/app.config | 15 - .../Delegate/NotifyCompleteEventHandler.cs | 9 - SiMay.Sockets/Properties/AssemblyInfo.cs | 36 -- SiMay.Sockets/README.md | 0 SiMay.Sockets/SiMay.Socket.sln | 31 -- SiMay.Sockets/SiMay.Sockets.csproj | 68 ---- SiMay.Sockets/Tcp/Pooling/SaeaAwaiterPool.cs | 50 --- SiMay.Sockets/Tcp/Pooling/SessionPool.cs | 49 --- .../Tcp/Session/TcpSocketSaeaFullBased.cs | 186 ---------- .../Tcp/Session/TcpSocketSaeaPackBased.cs | 301 ---------------- .../Tcp/Session/TcpSocketSaeaSession.cs | 70 ---- .../ITcpSocketSaeaConfiguration.cs | 17 - .../TcpSocketSaeaClientConfiguration.cs | 13 - .../TcpSocketSaeaServerConfiguration.cs | 17 - SiMay.Sockets/Tcp/TcpSocketConnectionState.cs | 15 - SiMay.Sockets/app.config | 15 - SiMay.UpdateClient/Program.cs | 41 --- SiMay.UpdateClient/Properties/AssemblyInfo.cs | 36 -- .../Properties/Resources.Designer.cs | 71 ---- SiMay.UpdateClient/Properties/Resources.resx | 117 ------- .../Properties/Settings.Designer.cs | 30 -- .../Properties/Settings.settings | 7 - SiMay.UpdateClient/SiMay.UpdateClient.csproj | 69 ---- SiMay.UpdateClient/SiMaySeriver.NewCore.mm | Bin 178176 -> 0 bytes SiMayRemoteManager.sln | 111 ++---- SiMaySerializeTestApp2/App.config | 6 + SiMaySerializeTestApp2/Program.cs | 83 +++++ .../Properties/AssemblyInfo.cs | 10 +- .../SiMaySerializeTestApp2.csproj | 27 +- 281 files changed, 2991 insertions(+), 5327 deletions(-) rename SiMay.Basic/{CompressHelper.cs => GZipHelper.cs} (98%) delete mode 100644 SiMay.Basic/ImageHelper.cs rename SiMay.Core/{ByteConverter.cs => Common/ByteConverterHelper.cs} (98%) rename SiMay.Core/{ => Common}/FileIconUtil.cs (99%) rename SiMay.Core/Packets/{OpenDialogPack.cs => ActivedApplicationPack.cs} (52%) rename SiMay.Core/Packets/Screen/{ScreenMKeyPack.cs => ScreenKeyPack.cs} (78%) delete mode 100644 SiMay.Daemon/Program.cs rename SiMay.Net.SessionProvider/{SendMessageHelper.cs => MessageHelper.cs} (68%) rename SiMay.Net.SessionProvider/SessionBased/{SessionHandle.cs => SessionProviderContext.cs} (49%) delete mode 100644 SiMay.Net.SessionProviderService/Packet/AckPacket.cs delete mode 100644 SiMay.Net.SessionProviderService/Packet/PackDeserializeSetup.cs delete mode 100644 SiMay.Net.SessionProviderService/Packet/PackSerializeSetup.cs delete mode 100644 SiMay.Net.SessionProviderService/Packet/PacketBuilderHelper.cs rename SiMay.Sockets/Tcp/TcpSocketCompletionNotify.cs => SiMay.Net.SessionProviderService/SysContact.cs (34%) rename SiMay.Net.SessionProviderService/{TcpChannelContext.cs => TcpSessionChannelContext.cs} (65%) delete mode 100644 SiMay.RemoteClient.NewCore/ApplicationService/ProcessSpy.cs delete mode 100644 SiMay.RemoteClient.NewCore/ApplicationService/ServiceManagerBase.cs rename {SiMay.Core => SiMay.RemoteClient.NewCore/Helper}/RegValueHelper.cs (100%) delete mode 100644 SiMay.RemoteClient.NewCore/MainService/ManagerTaskQueue.cs rename SiMay.RemoteClient.NewCore/MainService/{UpdateService.cs => ServiceTaskQueue.cs} (31%) rename SiMay.RemoteClient.NewCore/MainService/{ComputerSessionHelper.cs => SystemSessionHelper.cs} (96%) create mode 100644 SiMay.RemoteClient.NewCore/ServiceBase/ApplicationProtocolService.cs create mode 100644 SiMay.RemoteClient.NewCore/ServiceBase/ApplicationRemoteService.cs create mode 100644 SiMay.RemoteClient.NewCore/ServiceBase/ApplicationServiceBase.cs rename SiMay.Sockets/Tcp/TcpSocketSaeaSessionType.cs => SiMay.RemoteClient.NewCore/ServiceBase/MainApplicationService.cs (45%) rename SiMay.RemoteControlsCore/{HandlerAdapters/AdapterHandlerBase.cs => AdapterHandlerBase/ApplicationAdapterHandler.cs} (39%) create mode 100644 SiMay.RemoteControlsCore/AdapterHandlerBase/ApplicationProtocolAdapterHandler.cs create mode 100644 SiMay.RemoteControlsCore/AdapterHandlerBase/MainApplicationAdapterHandler.cs rename SiMay.RemoteControlsCore/{HandlerAdapters => ApplicationAdapterHandler}/AudioAdapterHandler.cs (64%) rename SiMay.RemoteControlsCore/{HandlerAdapters => ApplicationAdapterHandler}/FileCommon/AwaitAutoResetEvent.cs (100%) rename SiMay.RemoteControlsCore/{HandlerAdapters => ApplicationAdapterHandler}/KeyboardAdapterHandler.cs (64%) rename SiMay.RemoteControlsCore/{HandlerAdapters => ApplicationAdapterHandler}/RegistryEditorAdapterHandler.cs (81%) rename SiMay.RemoteControlsCore/{HandlerAdapters => ApplicationAdapterHandler}/RemoteFileAdapterHandler.cs (85%) rename SiMay.RemoteControlsCore/{HandlerAdapters => ApplicationAdapterHandler}/RemoteScreenAdapterHandler.cs (70%) rename SiMay.RemoteControlsCore/{HandlerAdapters => ApplicationAdapterHandler}/ShellAdapterHandler.cs (72%) rename SiMay.RemoteControlsCore/{HandlerAdapters => ApplicationAdapterHandler}/StartupAdapterHandler.cs (80%) rename SiMay.RemoteControlsCore/{HandlerAdapters => ApplicationAdapterHandler}/SystemAdapterHandler.cs (68%) rename SiMay.RemoteControlsCore/{HandlerAdapters => ApplicationAdapterHandler}/TcpConnectionAdapterHandler.cs (69%) rename SiMay.RemoteControlsCore/{HandlerAdapters => ApplicationAdapterHandler}/VideoAppAdapterHandler.cs (72%) delete mode 100644 SiMay.RemoteControlsCore/Helper/ServiceCOMHelper.cs rename SiMay.RemoteControlsCore/{AppMainAdapterHandler.cs => MainApplicationAdapterHandler.cs} (73%) delete mode 100644 SiMay.RemoteControlsCore/ResetPool.cs rename {SiMay.RemoteService => SiMay.RemoteService.Loader}/AppConfiguartion.cs (98%) rename {SiMay.RemoteService => SiMay.RemoteService.Loader}/CommonHelper.cs (98%) rename {SiMay.RemoteService => SiMay.RemoteService.Loader}/Entitys/StartParameter.cs (93%) rename {SiMay.RemoteService => SiMay.RemoteService.Loader}/FodyWeavers.xml (100%) rename {SiMay.RemoteService => SiMay.RemoteService.Loader}/Interface/IAppMainService.cs (85%) rename {SiMay.RemoteService => SiMay.RemoteService.Loader}/MessageHelper.cs (96%) rename {SiMay.RemoteService => SiMay.RemoteService.Loader}/Program.cs (99%) rename {SiMay.RemoteService => SiMay.RemoteService.Loader}/Properties/AssemblyInfo.cs (91%) rename {SiMay.RemoteService => SiMay.RemoteService.Loader}/Properties/app.manifest (100%) rename {SiMay.RemoteService => SiMay.RemoteService.Loader}/RegValueHelper.cs (96%) rename SiMay.RemoteService/SiMay.RemoteService.csproj => SiMay.RemoteService.Loader/SiMay.RemoteService.Loader.csproj (90%) rename {SiMay.RemoteService => SiMay.RemoteService.Loader}/SystemInforUtil.cs (98%) rename {SiMay.Daemon => SiMay.RemoteService.Loader}/app.config (74%) rename {SiMay.RemoteService => SiMay.RemoteService.Loader}/packages.config (60%) rename SiMay.Serialize/{ReflectCache => ReflectCachePool}/DynamicMethodMemberAccessor.cs (81%) rename SiMay.RemoteClient.NewCore/MainService/DesktopRecordManager.cs => SiMay.Serialize/ReflectCachePool/EntitySerializerBase.cs (57%) rename SiMay.Serialize/{ReflectCache => ReflectCachePool}/IMemberAccessor.cs (92%) rename {SiMay.Sockets.V4 => SiMay.Sockets.Standard}/Delegate/NotifyCompleteEventHandler.cs (100%) create mode 100644 SiMay.Sockets.Standard/SiMay.Sockets.Standard.csproj rename {SiMay.Sockets => SiMay.Sockets.Standard}/Tcp/Awaitable/SaeaAwaiter.cs (93%) rename {SiMay.Sockets => SiMay.Sockets.Standard}/Tcp/Awaitable/SaeaExHelper.cs (83%) rename {SiMay.Sockets => SiMay.Sockets.Standard}/Tcp/Client/TcpSocketSaeaClientAgent.cs (52%) rename {SiMay.Sockets => SiMay.Sockets.Standard}/Tcp/Pooling/ObjectPool.cs (100%) rename {SiMay.Sockets.V4 => SiMay.Sockets.Standard}/Tcp/Pooling/SaeaAwaiterPool.cs (100%) rename {SiMay.Sockets.V4 => SiMay.Sockets.Standard}/Tcp/Pooling/SessionPool.cs (100%) rename {SiMay.Sockets => SiMay.Sockets.Standard}/Tcp/Server/TcpSocketSaeaServer.cs (57%) rename {SiMay.Sockets.V4 => SiMay.Sockets.Standard}/Tcp/Session/TcpSocketSaeaFullBased.cs (51%) rename {SiMay.Sockets.V4 => SiMay.Sockets.Standard}/Tcp/Session/TcpSocketSaeaPackBased.cs (51%) rename {SiMay.Sockets.V4 => SiMay.Sockets.Standard}/Tcp/Session/TcpSocketSaeaSession.cs (44%) rename {SiMay.Sockets.V4 => SiMay.Sockets.Standard}/Tcp/TcpConfiguration/ITcpSocketSaeaConfiguration.cs (100%) rename {SiMay.Sockets => SiMay.Sockets.Standard}/Tcp/TcpConfiguration/TcpSocketConfigurationBase.cs (95%) rename {SiMay.Sockets.V4 => SiMay.Sockets.Standard}/Tcp/TcpConfiguration/TcpSocketSaeaClientConfiguration.cs (100%) rename {SiMay.Sockets.V4 => SiMay.Sockets.Standard}/Tcp/TcpConfiguration/TcpSocketSaeaServerConfiguration.cs (100%) rename {SiMay.Sockets.V4 => SiMay.Sockets.Standard}/Tcp/TcpSocketCompletionNotify.cs (100%) rename {SiMay.Sockets.V4 => SiMay.Sockets.Standard}/Tcp/TcpSocketConnectionState.cs (100%) rename {SiMay.Sockets => SiMay.Sockets.Standard}/Tcp/TcpSocketSaeaEngineBased.cs (33%) rename {SiMay.Sockets.V4 => SiMay.Sockets.Standard}/Tcp/TcpSocketSaeaSessionType.cs (100%) rename {SiMay.Sockets => SiMay.Sockets.Standard}/Tcp/TcpSocketsFactory.cs (90%) rename SiMay.Sockets/UtilityHelper/CompressHelper.cs => SiMay.Sockets.Standard/UtilityHelper/DeCompressHelper.cs (90%) rename {SiMay.Sockets => SiMay.Sockets.Standard}/UtilityHelper/LogHelper.cs (55%) delete mode 100644 SiMay.Sockets.V4/README.md delete mode 100644 SiMay.Sockets.V4/SiMay.Socket.sln delete mode 100644 SiMay.Sockets.V4/SiMay.Sockets.V4.csproj delete mode 100644 SiMay.Sockets.V4/Tcp/Awaitable/SaeaAwaiter.cs delete mode 100644 SiMay.Sockets.V4/Tcp/Awaitable/SaeaExHelper.cs delete mode 100644 SiMay.Sockets.V4/Tcp/Client/TcpSocketSaeaClientAgent.cs delete mode 100644 SiMay.Sockets.V4/Tcp/Pooling/ObjectPool.cs delete mode 100644 SiMay.Sockets.V4/Tcp/Server/TcpSocketSaeaServer.cs delete mode 100644 SiMay.Sockets.V4/Tcp/TcpConfiguration/TcpSocketConfigurationBase.cs delete mode 100644 SiMay.Sockets.V4/Tcp/TcpSocketSaeaEngineBased.cs delete mode 100644 SiMay.Sockets.V4/Tcp/TcpSocketsFactory.cs delete mode 100644 SiMay.Sockets.V4/UtilityHelper/CompressHelper.cs delete mode 100644 SiMay.Sockets.V4/UtilityHelper/LogHelper.cs delete mode 100644 SiMay.Sockets.V4/app.config delete mode 100644 SiMay.Sockets/Delegate/NotifyCompleteEventHandler.cs delete mode 100644 SiMay.Sockets/Properties/AssemblyInfo.cs delete mode 100644 SiMay.Sockets/README.md delete mode 100644 SiMay.Sockets/SiMay.Socket.sln delete mode 100644 SiMay.Sockets/SiMay.Sockets.csproj delete mode 100644 SiMay.Sockets/Tcp/Pooling/SaeaAwaiterPool.cs delete mode 100644 SiMay.Sockets/Tcp/Pooling/SessionPool.cs delete mode 100644 SiMay.Sockets/Tcp/Session/TcpSocketSaeaFullBased.cs delete mode 100644 SiMay.Sockets/Tcp/Session/TcpSocketSaeaPackBased.cs delete mode 100644 SiMay.Sockets/Tcp/Session/TcpSocketSaeaSession.cs delete mode 100644 SiMay.Sockets/Tcp/TcpConfiguration/ITcpSocketSaeaConfiguration.cs delete mode 100644 SiMay.Sockets/Tcp/TcpConfiguration/TcpSocketSaeaClientConfiguration.cs delete mode 100644 SiMay.Sockets/Tcp/TcpConfiguration/TcpSocketSaeaServerConfiguration.cs delete mode 100644 SiMay.Sockets/Tcp/TcpSocketConnectionState.cs delete mode 100644 SiMay.Sockets/app.config delete mode 100644 SiMay.UpdateClient/Program.cs delete mode 100644 SiMay.UpdateClient/Properties/AssemblyInfo.cs delete mode 100644 SiMay.UpdateClient/Properties/Resources.Designer.cs delete mode 100644 SiMay.UpdateClient/Properties/Resources.resx delete mode 100644 SiMay.UpdateClient/Properties/Settings.Designer.cs delete mode 100644 SiMay.UpdateClient/Properties/Settings.settings delete mode 100644 SiMay.UpdateClient/SiMay.UpdateClient.csproj delete mode 100644 SiMay.UpdateClient/SiMaySeriver.NewCore.mm create mode 100644 SiMaySerializeTestApp2/App.config create mode 100644 SiMaySerializeTestApp2/Program.cs rename {SiMay.Sockets.V4 => SiMaySerializeTestApp2}/Properties/AssemblyInfo.cs (76%) rename SiMay.Daemon/SiMay.Daemon.csproj => SiMaySerializeTestApp2/SiMaySerializeTestApp2.csproj (70%) diff --git a/README.md b/README.md index ab8c323..eaecf03 100644 --- a/README.md +++ b/README.md @@ -94,7 +94,8 @@ ### 6.0更新 1. 跨.NET Core支持,完善中间会话服务器、Web端实时监控管理 --未完成 -2. 二进制序列器性能优化,提升系统性能 -- 未完成 +2. 二进制序列化器采用反射缓存,提高系统性能 -- 2020.1.25 +3.屏幕视图轮播 --2020.1.15 ### 5.0更新 1. 优化了通讯库,支持FULL丶PACK数据处理方式,更友好的配置接口 @@ -107,7 +108,7 @@ 8. 被控服务实现了服务方式安装,实现了Session隔离穿透捕获桌面(锁屏,UAC), --11.9 9. 文件管理功能增强,重构文件夹传输 2019.7.13 10. 系统传输数据实体化 -- 2019-6-4 -11. 二进制序列化器采用反射缓存,提高系统性能 --待实现 +11. 二进制序列化器采用反射缓存,提高系统性能 --已实现 12. 远程桌面增加质量调整,低速率网络下控制更加流畅 -- 7.27 13. 支持远程更新服务端 -- 7.27 14. 增加列表排序功能 -- 7.27 diff --git a/SiMay.Basic/CompressHelper.cs b/SiMay.Basic/GZipHelper.cs similarity index 98% rename from SiMay.Basic/CompressHelper.cs rename to SiMay.Basic/GZipHelper.cs index 2e28233..6d1548a 100644 --- a/SiMay.Basic/CompressHelper.cs +++ b/SiMay.Basic/GZipHelper.cs @@ -7,7 +7,7 @@ using System.Text; namespace SiMay.Basic { - public class CompressHelper + public class GZipHelper { public static byte[] Compress(byte[] data, int offset, int lenght) diff --git a/SiMay.Basic/ImageHelper.cs b/SiMay.Basic/ImageHelper.cs deleted file mode 100644 index 44ad7be..0000000 --- a/SiMay.Basic/ImageHelper.cs +++ /dev/null @@ -1,36 +0,0 @@ -using System; -using System.Collections.Generic; -using System.Drawing; -using System.Drawing.Drawing2D; -using System.Drawing.Imaging; -using System.IO; -using System.Linq; -using System.Runtime.InteropServices; -using System.Text; - -namespace SiMay.Core.ScreenSpy -{ - /// - /// 通用屏幕图像处理类 - /// - public class ImageHelper - { - public static Bitmap SizeImage(Image srcImage, Size size) - { - try - { - Bitmap bitmap = new Bitmap(srcImage, size.Width, size.Height); - //Graphics g = Graphics.FromImage(bitmap); - - //g.InterpolationMode = InterpolationMode.HighQualityBicubic; - //g.DrawImage(srcImage, new Rectangle(0, 0, width, height), new Rectangle(0, 0, srcImage.Width, srcImage.Height), GraphicsUnit.Pixel); - //g.Dispose(); - return bitmap; - } - catch - { - return null; - } - } - } -} diff --git a/SiMay.Basic/ObjectHelper.cs b/SiMay.Basic/ObjectHelper.cs index 2649902..ed979ee 100644 --- a/SiMay.Basic/ObjectHelper.cs +++ b/SiMay.Basic/ObjectHelper.cs @@ -11,5 +11,10 @@ namespace SiMay.Basic { return (T)obj; } + + public static bool IsNull(this object obj) + { + return obj == null; + } } } diff --git a/SiMay.Basic/SiMay.Basic.csproj b/SiMay.Basic/SiMay.Basic.csproj index 15cbd87..9b5e5dd 100644 --- a/SiMay.Basic/SiMay.Basic.csproj +++ b/SiMay.Basic/SiMay.Basic.csproj @@ -9,9 +9,10 @@ Properties SiMay.Basic SiMay.Basic - v4.0 + v4.6.1 512 true + true @@ -22,6 +23,7 @@ prompt 4 8.0 + false pdbonly @@ -31,6 +33,7 @@ prompt 4 8.0 + false @@ -45,7 +48,7 @@ - + @@ -56,7 +59,6 @@ - diff --git a/SiMay.Core/ByteConverter.cs b/SiMay.Core/Common/ByteConverterHelper.cs similarity index 98% rename from SiMay.Core/ByteConverter.cs rename to SiMay.Core/Common/ByteConverterHelper.cs index 800fc38..2ee16af 100644 --- a/SiMay.Core/ByteConverter.cs +++ b/SiMay.Core/Common/ByteConverterHelper.cs @@ -5,7 +5,7 @@ using System.Text; namespace SiMay.Core { - public class ByteConverter + public class ByteConverterHelper { private static byte NULL_BYTE = byte.MinValue; diff --git a/SiMay.Core/FileIconUtil.cs b/SiMay.Core/Common/FileIconUtil.cs similarity index 99% rename from SiMay.Core/FileIconUtil.cs rename to SiMay.Core/Common/FileIconUtil.cs index b6588ae..e8ae2da 100644 --- a/SiMay.Core/FileIconUtil.cs +++ b/SiMay.Core/Common/FileIconUtil.cs @@ -122,6 +122,7 @@ namespace SiMay.Core { FileInfomation _FileInfomation = new FileInfomation(); IntPtr _IconIntPtr; + CoInitialize(IntPtr.Zero); if (isLargeIcon) { _IconIntPtr = SHGetFileInfo(@"", 0, ref _FileInfomation, (uint)Marshal.SizeOf(_FileInfomation), ((uint)FileInfoFlags.SHGFI_ICON | (uint)FileInfoFlags.SHGFI_LARGEICON)); diff --git a/SiMay.Core/Common/RegValueHelper.cs b/SiMay.Core/Common/RegValueHelper.cs index d34dfad..51e2091 100644 --- a/SiMay.Core/Common/RegValueHelper.cs +++ b/SiMay.Core/Common/RegValueHelper.cs @@ -26,16 +26,16 @@ namespace SiMay.Core.Common case RegistryValueKind.Binary: return value.Data.Length > 0 ? BitConverter.ToString(value.Data).Replace("-", " ").ToLower() : "(zero-length binary value)"; case RegistryValueKind.MultiString: - return string.Join(" ", ByteConverter.ToStringArray(value.Data)); + return string.Join(" ", ByteConverterHelper.ToStringArray(value.Data)); case RegistryValueKind.DWord: - var dword = ByteConverter.ToUInt32(value.Data); + var dword = ByteConverterHelper.ToUInt32(value.Data); return $"0x{dword:x8} ({dword})"; // show hexadecimal and decimal case RegistryValueKind.QWord: - var qword = ByteConverter.ToUInt64(value.Data); + var qword = ByteConverterHelper.ToUInt64(value.Data); return $"0x{qword:x8} ({qword})"; // show hexadecimal and decimal case RegistryValueKind.String: case RegistryValueKind.ExpandString: - return ByteConverter.ToString(value.Data); + return ByteConverterHelper.ToString(value.Data); default: return string.Empty; } diff --git a/SiMay.Core/Common/RegistryKeyHelper.cs b/SiMay.Core/Common/RegistryKeyHelper.cs index ce5fe53..4d7432b 100644 --- a/SiMay.Core/Common/RegistryKeyHelper.cs +++ b/SiMay.Core/Common/RegistryKeyHelper.cs @@ -131,17 +131,17 @@ namespace SiMay.Core.Common newRegValue.Data = (byte[]) value; break; case RegistryValueKind.MultiString: - newRegValue.Data = ByteConverter.GetBytes((string[]) value); + newRegValue.Data = ByteConverterHelper.GetBytes((string[]) value); break; case RegistryValueKind.DWord: - newRegValue.Data = ByteConverter.GetBytes((uint) (int) value); + newRegValue.Data = ByteConverterHelper.GetBytes((uint) (int) value); break; case RegistryValueKind.QWord: - newRegValue.Data = ByteConverter.GetBytes((ulong) (long) value); + newRegValue.Data = ByteConverterHelper.GetBytes((ulong) (long) value); break; case RegistryValueKind.String: case RegistryValueKind.ExpandString: - newRegValue.Data = ByteConverter.GetBytes((string) value); + newRegValue.Data = ByteConverterHelper.GetBytes((string) value); break; } } diff --git a/SiMay.Core/Extensions/RegistryKeyExtensions.cs b/SiMay.Core/Extensions/RegistryKeyExtensions.cs index 21c24cb..0b9cc4f 100644 --- a/SiMay.Core/Extensions/RegistryKeyExtensions.cs +++ b/SiMay.Core/Extensions/RegistryKeyExtensions.cs @@ -246,16 +246,16 @@ namespace SiMay.Core.Extensions { case RegistryValueKind.String: case RegistryValueKind.ExpandString: - data = ByteConverter.ToString((byte[]) data); + data = ByteConverterHelper.ToString((byte[]) data); break; case RegistryValueKind.DWord: - data = ByteConverter.ToUInt32((byte[]) data); + data = ByteConverterHelper.ToUInt32((byte[]) data); break; case RegistryValueKind.QWord: - data = ByteConverter.ToUInt64((byte[]) data); + data = ByteConverterHelper.ToUInt64((byte[]) data); break; case RegistryValueKind.MultiString: - data = ByteConverter.ToStringArray((byte[]) data); + data = ByteConverterHelper.ToStringArray((byte[]) data); break; } } diff --git a/SiMay.Core/MessageHead.cs b/SiMay.Core/MessageHead.cs index 6e80b6f..1b5cc39 100644 --- a/SiMay.Core/MessageHead.cs +++ b/SiMay.Core/MessageHead.cs @@ -5,8 +5,8 @@ namespace SiMay.Core { /// - /// S_XX :表示控制端接收的命令头 - /// C_XX :表示服务端接收的命令头 + /// S_ :表示控制端接收的命令头 + /// C_ :表示服务端接收的命令头 /// public enum MessageHead { @@ -17,192 +17,181 @@ namespace SiMay.Core //主窗体------------------------------------------------------------ S_MAIN_REMARK = 1000, //备注 - S_MAIN_ACTIVATE_CTRLSERVICE, //创建功能服务 + S_MAIN_ACTIVATE_APPLICATIONSERVICE, //创建功能服务 S_MAIN_SESSION, //会话管理 S_MAIN_HTTPDOWNLOAD, //下载 - S_MAIN_OPEN_WEBURL, //打开URL + S_MAIN_OPEN_WEBURL, //打开URL S_MAIN_MESSAGEBOX, //MessageBox - S_MAIN_DESKTOPVIEW, //屏幕查看 - S_MAIN_SCREENWALL_GETIMG, //获取屏幕 - S_MAIN_USERDESKTOP_CLOSE, //关闭屏幕墙 - S_MAIN_SCREEN_RECORD_OPEN, //设置屏幕记录 - S_MAIN_SCREEN_RECORD_CLOSE, //关闭屏幕记录 - S_MAIN_SCREEN_RECORD_GETIMG, //获取下一帧屏幕记录数据 + S_MAIN_CREATE_DESKTOPVIEW, //屏幕查看 + S_MAIN_DESKTOPVIEW_GETFRAME, //获取屏幕 + S_MAIN_DESKTOPVIEW_CLOSE, //关闭屏幕墙 + S_MAIN_DESKTOPRECORD_OPEN, //设置屏幕记录 + S_MAIN_DESKTOPRECORD_CLOSE, //关闭屏幕记录 + S_MAIN_DESKTOPRECORD_GETFRAME, //获取下一帧屏幕记录数据 S_MAIN_GROUP, //分组 S_MAIN_UPDATE, //远程更新 S_MAIN_PLUGIN_FILES, //插件文件 S_MAIN_RELOADER, //重新载入服务端程序(重启进程) - S_MAIN_INSTANLL_SERVICE, //服务安装 - S_MAIN_UNINSTANLL_SERVICE, //卸载服务 + S_MAIN_INSTANLL_SERVICE, //服务安装 + S_MAIN_UNINSTANLL_SERVICE, //卸载服务 //接收指令 C_MAIN_LOGIN = 2000, //上线信息 - C_MAIN_ACTIVE_APP, //打开窗口 - C_MAIN_USERDESKTOP_CREATE, //创建屏幕查看控件 - C_MAIN_SCREENWALL_IMG, //屏幕墙数据 - C_MAIN_SCREEN_RECORD_IMG, //屏幕记录数据 - C_MAIN_SCREEN_RECORD_OPEN, //打开桌面录制任务 - //C_MAIN_GET_PLUGIN_FILES, //下载插件 - //C_MAIN_TEMP_LOGIN, //临时上线信息(插件未加载状态) + C_MAIN_ACTIVE_APP, //打开窗口 + C_MAIN_DESKTOPVIEW_CREATE, //创建屏幕查看控件 + C_MAIN_DESKTOPVIEW_FRAME, //屏幕墙数据 + C_MAIN_DESKTOPRECORD_FRAME, //屏幕记录数据 + C_MAIN_DESKTOPRECORD_OPEN, //打开桌面录制任务 + C_MAIN_GET_PLUGIN_FILES, //下载插件 + C_MAIN_TEMP_LOGIN, //临时上线信息(插件未加载状态) //远程桌面------------------------------------------------------------------------ - S_SCREEN_NEXT_SCREENBITMP = 1000, //请求获取图像数据 + S_SCREEN_NEXT_SCREENBITMP = 1000, //请求获取图像数据 S_SCREEN_MOUSEKEYEVENT, //鼠键操作 S_SCREEN_MOUSEBLOCK, //鼠标锁定 S_SCREEN_BLACKSCREEN, //黑屏 - S_SCREEN_SET_CLIPBOARD_TEXT, //设置剪贴板内容 + S_SCREEN_SET_CLIPBOARD_TEXT, //设置剪贴板内容 S_SCREEN_RESET, //改变屏幕位色 S_SCREEN_CHANGESCANMODE, //改变扫描方式 S_SCREEN_SETQTY, //设置图像质量 - S_SCREEN_GET_CLIPOARD_TEXT, //获取剪切板Text - S_SCREEN_GET_INIT_BITINFO, //获取初始化屏幕信息 - S_SCREEN_CTRL_ALT_DEL, //模拟Ctrl+Alt+Del - S_SCREEN_CHANGE_MONITOR, //切换监视器 - S_SCREEN_DELETE_WALLPAPER, //移除壁纸 + S_SCREEN_GET_CLIPOARD_TEXT, //获取剪切板Text + S_SCREEN_GET_INIT_BITINFO, //获取初始化屏幕信息 + S_SCREEN_CTRL_ALT_DEL, //模拟Ctrl+Alt+Del + S_SCREEN_CHANGE_MONITOR, //切换监视器 + S_SCREEN_DELETE_WALLPAPER, //移除壁纸 C_SCREEN_BITINFO = 2000, //桌面大小信息 C_SCREEN_SCANCOMPLETE, //屏幕扫描完成 C_SCREEN_BITMP, //图像数据 C_SCREEN_DIFFBITMAP, //差异完整屏幕数据 - C_SCREEN_CLIPOARD_TEXT, //剪切板Text + C_SCREEN_CLIPOARD_TEXT, //剪切板Text //文件管理---------------------------------------------------------------- - S_FILE_GET_DRIVES = 1000, //发送驱动器列表 - S_FILE_GET_FILES, //打开目录 - S_FILE_EXECUTE, //打开文件 - S_FILE_DELETE, //删除 - S_FILE_CREATE_DIR, //创建文件夹 - S_FILE_RENAME, //文件重命名 - S_FILE_RENAME_FINISH, //重命名完成 - S_FILE_FILE_COPY, //复制文件 - S_FILE_FILE_PASTER, //粘贴文件 - S_FILE_DOWNLOAD, //下载文件 - S_FILE_OPEN_TEXT, //打开Text - S_FILE_UPLOAD, //上传文件 - S_FILE_NEXT_DATA, //下块数据 - //S_FILE_TRANSFER_FINISH, //上传完成 - S_FILE_FRIST_DATA, //首个数据包 - S_FILE_DATA, //文件数据 - S_FILE_STOP, //停止任务 - S_FILE_GETDIR_FILES, //获取文件夹中的文件 - //S_FILE_DIRECTORY_UPLOADINFO, //上传的文件夹信息 - //S_FILE_DIRECTORY_DOWNLOAD, //下载文件夹 - //S_FILE_CHANGEPOSITION, //改变断点 - S_FILE_TREE_DIR, //为树形控件获取指定目录所有文件夹 - S_FILE_REDIRION, //跳转路径 - - C_FILE_FILE_LIST = 2000, //文件列表 - C_FILE_CREATEF_DIR_FNISH, //文件夹创建完成 - //C_FILE_NEXTTASK, //下1个任务 - //C_FILE_FILE_INFO, //文件信息 - //C_FILE_FILE_UPLOAD, //上传文件 - C_FILE_OPEN_STATUS, //文件打开状态 - C_FILE_FRIST_DATA, //首个数据包 - C_FILE_NEXT_DATA, //下块数据 - C_FILE_DATA, //文件数据 - //C_FILE_TRANSFER_FINISH, //下载完成 - C_FILE_DELETE_FINISH, //删除完成 - C_FILE_PASTER_FINISH, //粘贴完成 - C_FILE_RENAME_FINISH, //重命名完成 - //C_FILE_DIRECTORY_UPLOAD, //上传文件夹 - //C_FILE_DIRECTORY_DOWNLOADINFO, //下载的文件夹信息 - //C_FILE_CHANGEPOSITION, //改变断点 - C_FILE_ERROR_INFO, //错误信息 - C_FILE_TEXT, //Text数据 - C_FILE_DIR_FILES, //文件夹内的文件 - C_FILE_COPY_FINISH, //复制文件完成 - C_FILE_TREE_DIRS, //树形控件文件夹信息 + S_FILE_GET_DRIVES = 1000, //发送驱动器列表 + S_FILE_GET_FILES, //打开目录 + S_FILE_EXECUTE, //打开文件 + S_FILE_DELETE, //删除 + S_FILE_CREATE_DIR, //创建文件夹 + S_FILE_RENAME, //文件重命名 + S_FILE_RENAME_FINISH, //重命名完成 + S_FILE_FILE_COPY, //复制文件 + S_FILE_FILE_PASTER, //粘贴文件 + S_FILE_DOWNLOAD, //下载文件 + S_FILE_OPEN_TEXT, //打开Text + S_FILE_UPLOAD, //上传文件 + S_FILE_NEXT_DATA, //下块数据 + S_FILE_FRIST_DATA, //首个数据包 + S_FILE_DATA, //文件数据 + S_FILE_STOP, //停止任务 + S_FILE_GETDIR_FILES, //获取文件夹中的文件 + S_FILE_TREE_DIR, //为树形控件获取指定目录所有文件夹 + S_FILE_REDIRION, //跳转路径 + + C_FILE_FILE_LIST = 2000, //文件列表 + C_FILE_CREATEF_DIR_FNISH, //文件夹创建完成 + C_FILE_OPEN_STATUS, //文件打开状态 + C_FILE_FRIST_DATA, //首个数据包 + C_FILE_NEXT_DATA, //下块数据 + C_FILE_DATA, //文件数据 + C_FILE_DELETE_FINISH, //删除完成 + C_FILE_PASTER_FINISH, //粘贴完成 + C_FILE_RENAME_FINISH, //重命名完成 + C_FILE_ERROR_INFO, //错误信息 + C_FILE_TEXT, //Text数据 + C_FILE_DIR_FILES, //文件夹内的文件 + C_FILE_COPY_FINISH, //复制文件完成 + C_FILE_TREE_DIRS, //树形控件文件夹信息 //SHELL------------------------------------------------------------------- - S_SHELL_INPUT = 1000, //执行CMD命令 + S_SHELL_INPUT = 1000, //执行CMD命令 - C_SHELL_RESULT = 2000, //SHELL结果 + C_SHELL_RESULT = 2000, //SHELL结果 //系统管理---------------------------------------------------------------- - S_SYSTEM_GET_PROCESS_LIST = 1000, //进程列表 - S_SYSTEM_GET_SYSTEMINFO, //系统信息 - S_SYSTEM_KILL, //结束进程 - S_SYSTEM_MAXIMIZE, //最大化窗口 - S_SYSTEM_MINIMIZE, //最小化窗体 - S_SYSTEM_GET_OCCUPY, //获取系统占用率信息 - S_SYSTEM_ENUMSESSIONS, //获取所有会话信息 - S_SYSTEM_CREATE_USER_PROCESS, //创建用户进程 + S_SYSTEM_GET_PROCESS_LIST = 1000, //进程列表 + S_SYSTEM_GET_SYSTEMINFO, //系统信息 + S_SYSTEM_KILL, //结束进程 + S_SYSTEM_MAXIMIZE, //最大化窗口 + S_SYSTEM_MINIMIZE, //最小化窗体 + S_SYSTEM_GET_OCCUPY, //获取系统占用率信息 + S_SYSTEM_ENUMSESSIONS, //获取所有会话信息 + S_SYSTEM_CREATE_USER_PROCESS, //创建用户进程 //接收指令 - C_SYSTEM_PROCESS_LIST = 2000, //进程列表 - C_SYSTEM_SYSTEMINFO, //系统信息 - C_SYSTEM_OCCUPY_INFO, //系统占用率信息 - C_SYSTEM_SESSIONS, //会话信息 + C_SYSTEM_PROCESS_LIST = 2000, //进程列表 + C_SYSTEM_SYSTEMINFO, //系统信息 + C_SYSTEM_OCCUPY_INFO, //系统占用率信息 + C_SYSTEM_SESSIONS, //会话信息 //键盘记录--------------------------------------------------------------- - S_KEYBOARD_ONOPEN = 1000, //窗口打开 - S_KEYBOARD_OFFLINE, //开始离线记录 - S_KEYBOARD_GET_OFFLINEFILE, //获取离线文件并停止离线记录 + S_KEYBOARD_ONOPEN = 1000, //窗口打开 + S_KEYBOARD_OFFLINE, //开始离线记录 + S_KEYBOARD_GET_OFFLINEFILE, //获取离线文件并停止离线记录 - C_KEYBOARD_DATA = 2000, //键盘记录数据 - C_KEYBOARD_OFFLINEFILE, //离线文件 + C_KEYBOARD_DATA = 2000, //键盘记录数据 + C_KEYBOARD_OFFLINEFILE, //离线文件 //语音监听--------------------------------------------------------------- - S_AUDIO_START, //开始语音 - S_AUDIO_DATA = 1000, //语音数据 - S_AUDIO_DEIVCE_ONOFF, //开关 + S_AUDIO_START, //开始语音 + S_AUDIO_DATA = 1000, //语音数据 + S_AUDIO_DEIVCE_ONOFF, //开关 - C_AUDIO_DATA = 2000, //语音数据 - C_AUDIO_DEVICE_OPENSTATE, //打开失败的设备 + C_AUDIO_DATA = 2000, //语音数据 + C_AUDIO_DEVICE_OPENSTATE, //打开失败的设备 //视频监控---------------------------------------------------------------- - S_VIEDO_GET_DATA = 1000, //获取图像 - S_VIEDO_RESET, //改变画质 + S_VIEDO_GET_DATA = 1000, //获取图像 + S_VIEDO_RESET, //改变画质 - C_VIEDO_DATA = 2000, //图像 - C_VIEDO_DEVICE_NOTEXIST, //未检测到视频设备 + C_VIEDO_DATA = 2000, //图像 + C_VIEDO_DEVICE_NOTEXIST, //未检测到视频设备 //注册表管理---------------------------------------------------------------- - S_REG_OPENDIRECTLY = 1000, //打开根目录 - S_REG_OPENSUBKEY, //打开子项 - S_REG_GETVALUES, //获取键值数据 - S_REG_CREATEVALUE, //创建键值 - S_REG_CREATESUBKEY, //创建项 - S_REG_DELETEVALUE, //删除键值 - S_REG_DELETESUBKEY, //删除子项 - S_REG_CHANGEVALUE, //修改键值数据 - - C_REG_ROOT_DIRSUBKEYNAMES = 2000, //根目录数据 - C_REG_SUBKEYNAMES, //子项数据 - C_REG_VALUENAMES, //键值数据 - C_REG_DELETESUBKEY_FINSH, //删除子项完成 - C_REG_CREATESUBKEY_FINSH, //创建子项完成 - C_REG_DELETEVALUE_FINSH, //删除键值完成 - - S_NREG_LOAD_REGKEYS = 1000, //加载键 - S_NREG_CREATE_KEY, //创建KEY - S_NREG_CREATE_VALUE, //创建值 - S_NREG_RENAME_KEY, //重命名键 - S_NREG_RENAME_VALUE, //重命名值 - S_NREG_DELETE_KEY, //删除键 - S_NREG_DELETE_VALUE, //删除值 - S_NREG_CHANGE_VALUE, //更改值 + S_REG_OPENDIRECTLY = 1000, //打开根目录 + S_REG_OPENSUBKEY, //打开子项 + S_REG_GETVALUES, //获取键值数据 + S_REG_CREATEVALUE, //创建键值 + S_REG_CREATESUBKEY, //创建项 + S_REG_DELETEVALUE, //删除键值 + S_REG_DELETESUBKEY, //删除子项 + S_REG_CHANGEVALUE, //修改键值数据 + + C_REG_ROOT_DIRSUBKEYNAMES = 2000, //根目录数据 + C_REG_SUBKEYNAMES, //子项数据 + C_REG_VALUENAMES, //键值数据 + C_REG_DELETESUBKEY_FINSH, //删除子项完成 + C_REG_CREATESUBKEY_FINSH, //创建子项完成 + C_REG_DELETEVALUE_FINSH, //删除键值完成 + + S_NREG_LOAD_REGKEYS = 1000, //加载键 + S_NREG_CREATE_KEY, //创建KEY + S_NREG_CREATE_VALUE, //创建值 + S_NREG_RENAME_KEY, //重命名键 + S_NREG_RENAME_VALUE, //重命名值 + S_NREG_DELETE_KEY, //删除键 + S_NREG_DELETE_VALUE, //删除值 + S_NREG_CHANGE_VALUE, //更改值 - C_NREG_LOAD_REGKEYS = 2000, //加载 - C_NREG_CREATE_KEY_RESPONSE, //创建KEY响应 - C_NREG_CREATE_VALUE_RESPONSE,//创建Value响应 - C_NREG_RENAME_KEY_RESPONSE, //重命名响应 - C_NREG_RENAME_VALUE_RESPONSE,//重命名值 - C_NREG_DELETE_KEY_RESPONSE, //删除键响应 - C_NREG_DELETE_VALUE_RESPONSE,//删除值响应 - C_NREG_CHANGE_VALUE_RESPONSE,//更改值响应 - - S_TCP_GET_LIST = 1000, //获取TCP连接列表 + C_NREG_LOAD_REGKEYS = 2000, //加载 + C_NREG_CREATE_KEY_RESPONSE, //创建KEY响应 + C_NREG_CREATE_VALUE_RESPONSE, //创建Value响应 + C_NREG_RENAME_KEY_RESPONSE, //重命名响应 + C_NREG_RENAME_VALUE_RESPONSE, //重命名值 + C_NREG_DELETE_KEY_RESPONSE, //删除键响应 + C_NREG_DELETE_VALUE_RESPONSE, //删除值响应 + C_NREG_CHANGE_VALUE_RESPONSE, //更改值响应 + + S_TCP_GET_LIST = 1000, //获取TCP连接列表 S_TCP_CLOSE_CHANNEL, - C_TCP_LIST = 2000, //关闭TCP连接 - C_TCP_CLOSE_ERROR_LIST, //关闭错误项 + C_TCP_LIST = 2000, //关闭TCP连接 + C_TCP_CLOSE_ERROR_LIST, //关闭错误项 - S_STARTUP_GET_LIST = 1000, //获取所有启动项 - S_STARTUP_ADD_ITEM, //添加启动项 - S_STARTUP_REMOVE_ITEM, //移除启动项目 + S_STARTUP_GET_LIST = 1000, //获取所有启动项 + S_STARTUP_ADD_ITEM, //添加启动项 + S_STARTUP_REMOVE_ITEM, //移除启动项目 - C_STARTUP_LIST = 2000, //启动项列表 - C_STARTUP_OPER_RESPONSE //操作结果 + C_STARTUP_LIST = 2000, //启动项列表 + C_STARTUP_OPER_RESPONSE //操作结果 } } \ No newline at end of file diff --git a/SiMay.Core/MessageHelper.cs b/SiMay.Core/MessageHelper.cs index 6bda8e2..43600ee 100644 --- a/SiMay.Core/MessageHelper.cs +++ b/SiMay.Core/MessageHelper.cs @@ -1,13 +1,12 @@ -using SiMay.Basic; +using System; using SiMay.Core.Extensions; -using System; -using System.Collections; -using System.Collections.Generic; using static SiMay.Serialize.PacketSerializeHelper; namespace SiMay.Core { - + /// + /// 消息处理帮助(格式:Int16的消息头 + payload) + /// public static class MessageHelper { /// @@ -86,9 +85,9 @@ namespace SiMay.Core /// public static byte[] GetMessagePayload(this byte[] data) { - byte[] bytes = new byte[data.Length - sizeof(short)]; - Array.Copy(data, sizeof(short), bytes, 0, bytes.Length); - return bytes; + byte[] payload = new byte[data.Length - sizeof(short)]; + Array.Copy(data, sizeof(short), payload, 0, payload.Length); + return payload; } /// diff --git a/SiMay.Core/Packets/AckPack.cs b/SiMay.Core/Packets/AckPack.cs index a04fd04..8fe2181 100644 --- a/SiMay.Core/Packets/AckPack.cs +++ b/SiMay.Core/Packets/AckPack.cs @@ -1,4 +1,5 @@ using SiMay.Core.Enums; +using SiMay.ReflectCache; using System; using System.Collections.Generic; using System.Linq; @@ -6,9 +7,11 @@ using System.Text; namespace SiMay.Core.Packets { - public class AckPack : BasePacket + public class AckPack : EntitySerializerBase { - public long AccessKey { get; set; } public ConnectionWorkType Type { get; set; } + public long AccessId { get; set; } + public long AccessKey { get; set; } + } } diff --git a/SiMay.Core/Packets/OpenDialogPack.cs b/SiMay.Core/Packets/ActivedApplicationPack.cs similarity index 52% rename from SiMay.Core/Packets/OpenDialogPack.cs rename to SiMay.Core/Packets/ActivedApplicationPack.cs index f87e154..d751d63 100644 --- a/SiMay.Core/Packets/OpenDialogPack.cs +++ b/SiMay.Core/Packets/ActivedApplicationPack.cs @@ -1,11 +1,16 @@ -using System; +using SiMay.ReflectCache; +using System; using System.Collections.Generic; using System.Linq; using System.Text; namespace SiMay.Core.Packets { - public class ActiveAppPack : BasePacket + public class ActivateServicePack : EntitySerializerBase + { + public string ApplicationKey { get; set; } + } + public class ActivateApplicationPack : EntitySerializerBase { public string IdentifyId { get; set; } public string ServiceKey { get; set; } diff --git a/SiMay.Core/Packets/Audio/AudioDeviceStatesPack.cs b/SiMay.Core/Packets/Audio/AudioDeviceStatesPack.cs index 0273f2e..5c4a84b 100644 --- a/SiMay.Core/Packets/Audio/AudioDeviceStatesPack.cs +++ b/SiMay.Core/Packets/Audio/AudioDeviceStatesPack.cs @@ -1,11 +1,12 @@ -using System; +using SiMay.ReflectCache; +using System; using System.Collections.Generic; using System.Linq; using System.Text; namespace SiMay.Core.Packets { - public class AudioDeviceStatesPack : BasePacket + public class AudioDeviceStatesPack : EntitySerializerBase { public bool PlayerEnable { get; set; } public bool RecordEnable { get; set; } diff --git a/SiMay.Core/Packets/Audio/AudioOptionsPack.cs b/SiMay.Core/Packets/Audio/AudioOptionsPack.cs index e956fb8..0746e16 100644 --- a/SiMay.Core/Packets/Audio/AudioOptionsPack.cs +++ b/SiMay.Core/Packets/Audio/AudioOptionsPack.cs @@ -1,11 +1,12 @@ -using System; +using SiMay.ReflectCache; +using System; using System.Collections.Generic; using System.Linq; using System.Text; namespace SiMay.Core.Packets { - public class AudioOptionsPack : BasePacket + public class AudioOptionsPack : EntitySerializerBase { public int SamplesPerSecond { get; set; } public int BitsPerSample { get; set; } diff --git a/SiMay.Core/Packets/DesktopRecordGetFramePack.cs b/SiMay.Core/Packets/DesktopRecordGetFramePack.cs index 644a6c1..c47bf7f 100644 --- a/SiMay.Core/Packets/DesktopRecordGetFramePack.cs +++ b/SiMay.Core/Packets/DesktopRecordGetFramePack.cs @@ -1,11 +1,12 @@ -using System; +using SiMay.ReflectCache; +using System; using System.Collections.Generic; using System.Linq; using System.Text; namespace SiMay.Core.Packets { - public class DesktopRecordGetFramePack : BasePacket + public class DesktopRecordGetFramePack : EntitySerializerBase { public int Height { get; set; } public int Width { get; set; } diff --git a/SiMay.Core/Packets/DesktopViewDescribePack.cs b/SiMay.Core/Packets/DesktopViewDescribePack.cs index 623c9e7..aaf588b 100644 --- a/SiMay.Core/Packets/DesktopViewDescribePack.cs +++ b/SiMay.Core/Packets/DesktopViewDescribePack.cs @@ -1,11 +1,12 @@ -using System; +using SiMay.ReflectCache; +using System; using System.Collections.Generic; using System.Linq; using System.Text; namespace SiMay.Core.Packets { - public class DesktopViewDescribePack : BasePacket + public class DesktopViewDescribePack : EntitySerializerBase { public string MachineName { get; set; } public string RemarkInformation { get; set; } diff --git a/SiMay.Core/Packets/DesktopViewGetFramePack.cs b/SiMay.Core/Packets/DesktopViewGetFramePack.cs index 2bca51e..e2ba178 100644 --- a/SiMay.Core/Packets/DesktopViewGetFramePack.cs +++ b/SiMay.Core/Packets/DesktopViewGetFramePack.cs @@ -1,11 +1,12 @@ -using System; +using SiMay.ReflectCache; +using System; using System.Collections.Generic; using System.Linq; using System.Text; namespace SiMay.Core.Packets { - public class DesktopViewGetFramePack : BasePacket + public class DesktopViewGetFramePack : EntitySerializerBase { public int Height { get; set; } public int Width { get; set; } @@ -13,7 +14,7 @@ namespace SiMay.Core.Packets public bool InVisbleArea { get; set; } } - public class DesktopViewFramePack : BasePacket + public class DesktopViewFramePack : EntitySerializerBase { public bool InVisbleArea { get; set; } public byte[] ViewData { get; set; } diff --git a/SiMay.Core/Packets/FileManager/FileCopyPack.cs b/SiMay.Core/Packets/FileManager/FileCopyPack.cs index f0dd85c..28985f9 100644 --- a/SiMay.Core/Packets/FileManager/FileCopyPack.cs +++ b/SiMay.Core/Packets/FileManager/FileCopyPack.cs @@ -1,4 +1,5 @@ -using System; +using SiMay.ReflectCache; +using System; using System.Collections.Generic; using System.Linq; using System.Text; @@ -8,7 +9,7 @@ namespace SiMay.Core.Packets.FileManager /// /// 复制文件 /// - public class FileCopyPack : BasePacket + public class FileCopyPack : EntitySerializerBase { public string[] FileNames { get; set; } public string TargetDirectoryPath { get; set; } @@ -16,7 +17,7 @@ namespace SiMay.Core.Packets.FileManager /// /// 复制结束 /// - public class FileCopyFinishPack : BasePacket + public class FileCopyFinishPack : EntitySerializerBase { /// /// 复制异常的文件 diff --git a/SiMay.Core/Packets/FileManager/FileCreateDirectoryPack.cs b/SiMay.Core/Packets/FileManager/FileCreateDirectoryPack.cs index b578ff6..cb72e4f 100644 --- a/SiMay.Core/Packets/FileManager/FileCreateDirectoryPack.cs +++ b/SiMay.Core/Packets/FileManager/FileCreateDirectoryPack.cs @@ -1,17 +1,18 @@ -using System; +using SiMay.ReflectCache; +using System; using System.Collections.Generic; using System.Linq; using System.Text; namespace SiMay.Core.Packets.FileManager { - public class FileCreateDirectoryPack : BasePacket + public class FileCreateDirectoryPack : EntitySerializerBase { public string DirectoryName { get; set; } public bool NoCallBack { get; set; } } - public class FileCreateDirectoryFinishPack : BasePacket + public class FileCreateDirectoryFinishPack : EntitySerializerBase { public bool IsSuccess { get; set; } } diff --git a/SiMay.Core/Packets/FileManager/FileDeletePack.cs b/SiMay.Core/Packets/FileManager/FileDeletePack.cs index ec1ee0f..379f6e8 100644 --- a/SiMay.Core/Packets/FileManager/FileDeletePack.cs +++ b/SiMay.Core/Packets/FileManager/FileDeletePack.cs @@ -1,4 +1,5 @@ -using System; +using SiMay.ReflectCache; +using System; using System.Collections.Generic; using System.Linq; using System.Text; @@ -8,11 +9,11 @@ namespace SiMay.Core.Packets.FileManager /// /// 删除文件 /// - public class FileDeletePack : BasePacket + public class FileDeletePack : EntitySerializerBase { public string[] FileNames { get; set; } } - public class FileDeleteFinishPack : BasePacket + public class FileDeleteFinishPack : EntitySerializerBase { /// /// 删除成功的文件 diff --git a/SiMay.Core/Packets/FileManager/FileDirectoryGetFilesPack.cs b/SiMay.Core/Packets/FileManager/FileDirectoryGetFilesPack.cs index 8ef8b21..2d3360a 100644 --- a/SiMay.Core/Packets/FileManager/FileDirectoryGetFilesPack.cs +++ b/SiMay.Core/Packets/FileManager/FileDirectoryGetFilesPack.cs @@ -1,4 +1,5 @@ -using System; +using SiMay.ReflectCache; +using System; using System.Collections.Generic; using System.Linq; using System.Text; @@ -8,12 +9,12 @@ namespace SiMay.Core.Packets.FileManager /// /// 获取文件夹文件 /// - public class FileDirectoryGetFilesPack : BasePacket + public class FileDirectoryGetFilesPack : EntitySerializerBase { public string DirectoryPath { get; set; } } - public class FileDirectoryFilesPack : BasePacket + public class FileDirectoryFilesPack : EntitySerializerBase { /// /// 文件信息 @@ -21,7 +22,7 @@ namespace SiMay.Core.Packets.FileManager public DirectoryFileItem[] Files { get; set; } } - public class DirectoryFileItem + public class DirectoryFileItem : EntitySerializerBase { public DirectoryFileType Type { get; set; } public string FileName { get; set; } diff --git a/SiMay.Core/Packets/FileManager/FileDownloadPack.cs b/SiMay.Core/Packets/FileManager/FileDownloadPack.cs index c0cea16..e6e3a67 100644 --- a/SiMay.Core/Packets/FileManager/FileDownloadPack.cs +++ b/SiMay.Core/Packets/FileManager/FileDownloadPack.cs @@ -1,4 +1,5 @@ -using System; +using SiMay.ReflectCache; +using System; using System.Collections.Generic; using System.Linq; using System.Text; @@ -8,7 +9,7 @@ namespace SiMay.Core.Packets.FileManager /// /// 文件下载 /// - public class FileDownloadPack : BasePacket + public class FileDownloadPack : EntitySerializerBase { public string FileName { get; set; } /// @@ -20,7 +21,7 @@ namespace SiMay.Core.Packets.FileManager /// /// 首数据包(减少交互快速传输文件) /// - public class FileFristDownloadDataPack : BasePacket + public class FileFristDownloadDataPack : EntitySerializerBase { //public string fileName { get; set; } /// @@ -37,7 +38,7 @@ namespace SiMay.Core.Packets.FileManager public byte[] Data { get; set; } } - public class FileDownloadDataPack : BasePacket + public class FileDownloadDataPack : EntitySerializerBase { public byte[] Data { get; set; } } diff --git a/SiMay.Core/Packets/FileManager/FileExceptionPack.cs b/SiMay.Core/Packets/FileManager/FileExceptionPack.cs index 3b8c9da..8d4b572 100644 --- a/SiMay.Core/Packets/FileManager/FileExceptionPack.cs +++ b/SiMay.Core/Packets/FileManager/FileExceptionPack.cs @@ -1,11 +1,12 @@ -using System; +using SiMay.ReflectCache; +using System; using System.Collections.Generic; using System.Linq; using System.Text; namespace SiMay.Core.Packets.FileManager { - public class FileExceptionPack : BasePacket + public class FileExceptionPack : EntitySerializerBase { public DateTime OccurredTime { get; set; } public string TipMessage { get; set; } diff --git a/SiMay.Core/Packets/FileManager/FileExcutePack.cs b/SiMay.Core/Packets/FileManager/FileExcutePack.cs index c1198fa..4d09b34 100644 --- a/SiMay.Core/Packets/FileManager/FileExcutePack.cs +++ b/SiMay.Core/Packets/FileManager/FileExcutePack.cs @@ -1,11 +1,12 @@ -using System; +using SiMay.ReflectCache; +using System; using System.Collections.Generic; using System.Linq; using System.Text; namespace SiMay.Core.Packets.FileManager { - public class FileExcutePack : BasePacket + public class FileExcutePack : EntitySerializerBase { public string FilePath { get; set; } } diff --git a/SiMay.Core/Packets/FileManager/FileGetTreeDirectoryPack.cs b/SiMay.Core/Packets/FileManager/FileGetTreeDirectoryPack.cs index 2f5b2ac..1793b93 100644 --- a/SiMay.Core/Packets/FileManager/FileGetTreeDirectoryPack.cs +++ b/SiMay.Core/Packets/FileManager/FileGetTreeDirectoryPack.cs @@ -1,16 +1,17 @@ -using System; +using SiMay.ReflectCache; +using System; using System.Collections.Generic; using System.Linq; using System.Text; namespace SiMay.Core.Packets.FileManager { - public class FileGetTreeDirectoryPack + public class FileGetTreeDirectoryPack : EntitySerializerBase { public string TargetRoot { get; set; } } - public class FileTreeDirFilePack + public class FileTreeDirFilePack : EntitySerializerBase { public FileItem[] FileList { get; set; } public string Message { get; set; } diff --git a/SiMay.Core/Packets/FileManager/FileListItemsPack.cs b/SiMay.Core/Packets/FileManager/FileListItemsPack.cs index 078dbab..a14e1b9 100644 --- a/SiMay.Core/Packets/FileManager/FileListItemsPack.cs +++ b/SiMay.Core/Packets/FileManager/FileListItemsPack.cs @@ -1,4 +1,5 @@ using SiMay.Core.Enums; +using SiMay.ReflectCache; using System; using System.Collections.Generic; using System.Linq; @@ -6,19 +7,19 @@ using System.Text; namespace SiMay.Core.Packets { - public class FileListPack : BasePacket + public class FileListPack : EntitySerializerBase { public string FilePath { get; set; } } - public class FileListItemsPack : BasePacket + public class FileListItemsPack : EntitySerializerBase { public FileItem[] FileList { get; set; } public string Path { get; set; } public string Message { get; set; } public bool IsSccessed { get; set; } } - public class FileItem + public class FileItem : EntitySerializerBase { public string FileName { get; set; } diff --git a/SiMay.Core/Packets/FileManager/FileReNamePack.cs b/SiMay.Core/Packets/FileManager/FileReNamePack.cs index bfdc667..3c9fffe 100644 --- a/SiMay.Core/Packets/FileManager/FileReNamePack.cs +++ b/SiMay.Core/Packets/FileManager/FileReNamePack.cs @@ -1,17 +1,18 @@ -using System; +using SiMay.ReflectCache; +using System; using System.Collections.Generic; using System.Linq; using System.Text; namespace SiMay.Core.Packets.FileManager { - public class FileReNamePack : BasePacket + public class FileReNamePack : EntitySerializerBase { public string SourceFileName { get; set; } public string TargetName { get; set; } } - public class FileReNameFinishPack : BasePacket + public class FileReNameFinishPack : EntitySerializerBase { public bool IsSuccess { get; set; } public string SourceFileName { get; set; } diff --git a/SiMay.Core/Packets/FileManager/FileRedirectionPath.cs b/SiMay.Core/Packets/FileManager/FileRedirectionPath.cs index 488243e..9ebf1e0 100644 --- a/SiMay.Core/Packets/FileManager/FileRedirectionPath.cs +++ b/SiMay.Core/Packets/FileManager/FileRedirectionPath.cs @@ -1,4 +1,5 @@ -using System; +using SiMay.ReflectCache; +using System; using System.Collections.Generic; using System.Linq; using System.Text; @@ -6,7 +7,7 @@ using static System.Environment; namespace SiMay.Core.Packets.FileManager { - public class FileRedirectionPath : BasePacket + public class FileRedirectionPath : EntitySerializerBase { public SpecialFolder SpecialFolder { get; set; } } diff --git a/SiMay.Core/Packets/FileManager/FileTextPack.cs b/SiMay.Core/Packets/FileManager/FileTextPack.cs index 8b44884..6a4f6df 100644 --- a/SiMay.Core/Packets/FileManager/FileTextPack.cs +++ b/SiMay.Core/Packets/FileManager/FileTextPack.cs @@ -1,15 +1,16 @@ -using System; +using SiMay.ReflectCache; +using System; using System.Collections.Generic; using System.Linq; using System.Text; namespace SiMay.Core.Packets.FileManager { - public class FileOpenTextPack : BasePacket + public class FileOpenTextPack : EntitySerializerBase { public string FileName { get; set; } } - public class FileTextPack : BasePacket + public class FileTextPack : EntitySerializerBase { /// /// 是否可以访问 diff --git a/SiMay.Core/Packets/FileManager/FileUploadPack.cs b/SiMay.Core/Packets/FileManager/FileUploadPack.cs index 0e5e242..cbc3025 100644 --- a/SiMay.Core/Packets/FileManager/FileUploadPack.cs +++ b/SiMay.Core/Packets/FileManager/FileUploadPack.cs @@ -1,16 +1,17 @@ -using System; +using SiMay.ReflectCache; +using System; using System.Collections.Generic; using System.Linq; using System.Text; namespace SiMay.Core.Packets.FileManager { - public class FileUploadPack : BasePacket + public class FileUploadPack : EntitySerializerBase { public string FileName { get; set; } } - public class FileUploadFileStatus : BasePacket + public class FileUploadFileStatus : EntitySerializerBase { /// /// 文件打开状态 0:文件不存在,1文件存在,2文件访问失败 @@ -19,7 +20,7 @@ namespace SiMay.Core.Packets.FileManager public long Position { get; set; } } - public class FileFristUploadDataPack : BasePacket + public class FileFristUploadDataPack : EntitySerializerBase { public int FileMode { get; set; } public long Position { get; set; } @@ -27,7 +28,7 @@ namespace SiMay.Core.Packets.FileManager public byte[] Data { get; set; } } - public class FileUploadDataPack : BasePacket + public class FileUploadDataPack : EntitySerializerBase { public long FileSize { get; set; } public byte[] Data { get; set; } diff --git a/SiMay.Core/Packets/LoginPack.cs b/SiMay.Core/Packets/LoginPack.cs index 5fde69b..43f7d7d 100644 --- a/SiMay.Core/Packets/LoginPack.cs +++ b/SiMay.Core/Packets/LoginPack.cs @@ -1,11 +1,12 @@ -using System; +using SiMay.ReflectCache; +using System; using System.Collections.Generic; using System.Linq; using System.Text; namespace SiMay.Core.Packets { - public class LoginPack : BasePacket + public class LoginPack : EntitySerializerBase { public string IPV4 { get; set; } public string MachineName { get; set; } diff --git a/SiMay.Core/Packets/MessagePack.cs b/SiMay.Core/Packets/MessagePack.cs index 59ef087..efb60b1 100644 --- a/SiMay.Core/Packets/MessagePack.cs +++ b/SiMay.Core/Packets/MessagePack.cs @@ -1,4 +1,5 @@ using SiMay.Core.Enums; +using SiMay.ReflectCache; using System; using System.Collections.Generic; using System.Linq; @@ -6,7 +7,7 @@ using System.Text; namespace SiMay.Core.Packets { - public class MessagePack : BasePacket + public class MessagePack : EntitySerializerBase { public byte MessageIcon { get; set; } diff --git a/SiMay.Core/Packets/Reg/RegDeleteSubKeyPack.cs b/SiMay.Core/Packets/Reg/RegDeleteSubKeyPack.cs index 5fdc9fd..091aba6 100644 --- a/SiMay.Core/Packets/Reg/RegDeleteSubKeyPack.cs +++ b/SiMay.Core/Packets/Reg/RegDeleteSubKeyPack.cs @@ -1,11 +1,12 @@ -using System; +using SiMay.ReflectCache; +using System; using System.Collections.Generic; using System.Linq; using System.Text; namespace SiMay.Core.Packets.Reg { - public class RegDeleteSubKeyPack : BasePacket + public class RegDeleteSubKeyPack : EntitySerializerBase { public string Root { get; set; } public string NodePath { get; set; } diff --git a/SiMay.Core/Packets/Reg/RegDeleteValuePack.cs b/SiMay.Core/Packets/Reg/RegDeleteValuePack.cs index f9c1a46..efae9ea 100644 --- a/SiMay.Core/Packets/Reg/RegDeleteValuePack.cs +++ b/SiMay.Core/Packets/Reg/RegDeleteValuePack.cs @@ -1,11 +1,12 @@ -using System; +using SiMay.ReflectCache; +using System; using System.Collections.Generic; using System.Linq; using System.Text; namespace SiMay.Core.Packets.Reg { - public class RegDeleteValuePack : BasePacket + public class RegDeleteValuePack : EntitySerializerBase { public string Root { get; set; } public string NodePath { get; set; } diff --git a/SiMay.Core/Packets/Reg/RegNewSubkeyPack.cs b/SiMay.Core/Packets/Reg/RegNewSubkeyPack.cs index 1671fde..330e5e0 100644 --- a/SiMay.Core/Packets/Reg/RegNewSubkeyPack.cs +++ b/SiMay.Core/Packets/Reg/RegNewSubkeyPack.cs @@ -1,11 +1,12 @@ -using System; +using SiMay.ReflectCache; +using System; using System.Collections.Generic; using System.Linq; using System.Text; namespace SiMay.Core.Packets.Reg { - public class RegNewSubkeyPack : BasePacket + public class RegNewSubkeyPack : EntitySerializerBase { public string Root { get; set; } public string NodePath { get; set; } diff --git a/SiMay.Core/Packets/Reg/RegNewValuePack.cs b/SiMay.Core/Packets/Reg/RegNewValuePack.cs index 5176a75..a52ed04 100644 --- a/SiMay.Core/Packets/Reg/RegNewValuePack.cs +++ b/SiMay.Core/Packets/Reg/RegNewValuePack.cs @@ -1,11 +1,12 @@ -using System; +using SiMay.ReflectCache; +using System; using System.Collections.Generic; using System.Linq; using System.Text; namespace SiMay.Core.Packets.Reg { - public class RegNewValuePack : BasePacket + public class RegNewValuePack : EntitySerializerBase { public string Root { get; set; } public string NodePath { get; set; } diff --git a/SiMay.Core/Packets/Reg/RegOpenSubKeyPack.cs b/SiMay.Core/Packets/Reg/RegOpenSubKeyPack.cs index 5aff9d1..335cf8c 100644 --- a/SiMay.Core/Packets/Reg/RegOpenSubKeyPack.cs +++ b/SiMay.Core/Packets/Reg/RegOpenSubKeyPack.cs @@ -1,11 +1,12 @@ -using System; +using SiMay.ReflectCache; +using System; using System.Collections.Generic; using System.Linq; using System.Text; namespace SiMay.Core.Packets.Reg { - public class RegOpenSubKeyPack : BasePacket + public class RegOpenSubKeyPack : EntitySerializerBase { public string Root { get; set; } public string NodePath { get; set; } diff --git a/SiMay.Core/Packets/Reg/RegOperFinshPack.cs b/SiMay.Core/Packets/Reg/RegOperFinshPack.cs index 507247f..e71c490 100644 --- a/SiMay.Core/Packets/Reg/RegOperFinshPack.cs +++ b/SiMay.Core/Packets/Reg/RegOperFinshPack.cs @@ -1,11 +1,12 @@ -using System; +using SiMay.ReflectCache; +using System; using System.Collections.Generic; using System.Linq; using System.Text; namespace SiMay.Core.Packets.Reg { - public class RegOperFinshPack : BasePacket + public class RegOperFinshPack : EntitySerializerBase { public bool Result { get; set; } public string Value { get; set; } diff --git a/SiMay.Core/Packets/Reg/RegRootDirectorysPack.cs b/SiMay.Core/Packets/Reg/RegRootDirectorysPack.cs index 6ae85aa..ab22f3e 100644 --- a/SiMay.Core/Packets/Reg/RegRootDirectorysPack.cs +++ b/SiMay.Core/Packets/Reg/RegRootDirectorysPack.cs @@ -1,11 +1,12 @@ -using System; +using SiMay.ReflectCache; +using System; using System.Collections.Generic; using System.Linq; using System.Text; namespace SiMay.Core.Packets.Reg { - public class RegRootDirectorysPack : BasePacket + public class RegRootDirectorysPack : EntitySerializerBase { public string[] RootDirectorys { get; set; } } diff --git a/SiMay.Core/Packets/Reg/RegSubKeyValuePack.cs b/SiMay.Core/Packets/Reg/RegSubKeyValuePack.cs index e088c52..3a19e8e 100644 --- a/SiMay.Core/Packets/Reg/RegSubKeyValuePack.cs +++ b/SiMay.Core/Packets/Reg/RegSubKeyValuePack.cs @@ -1,11 +1,12 @@ -using System; +using SiMay.ReflectCache; +using System; using System.Collections.Generic; using System.Linq; using System.Text; namespace SiMay.Core.Packets.Reg { - public class RegSubKeyValuePack : BasePacket + public class RegSubKeyValuePack : EntitySerializerBase { public string[] SubKeyNames { get; set; } public RegValueItem[] Values { get; set; } diff --git a/SiMay.Core/Packets/Reg/RegValueItem.cs b/SiMay.Core/Packets/Reg/RegValueItem.cs index a8a5c6b..0b23fe8 100644 --- a/SiMay.Core/Packets/Reg/RegValueItem.cs +++ b/SiMay.Core/Packets/Reg/RegValueItem.cs @@ -1,11 +1,12 @@ -using System; +using SiMay.ReflectCache; +using System; using System.Collections.Generic; using System.Linq; using System.Text; namespace SiMay.Core.Packets.Reg { - public class RegValueItem + public class RegValueItem : EntitySerializerBase { public string ValueName { get; set; } public string Value { get; set; } diff --git a/SiMay.Core/Packets/Reg/RegValuesPack.cs b/SiMay.Core/Packets/Reg/RegValuesPack.cs index 81f2c98..8a8f35d 100644 --- a/SiMay.Core/Packets/Reg/RegValuesPack.cs +++ b/SiMay.Core/Packets/Reg/RegValuesPack.cs @@ -1,11 +1,12 @@ -using System; +using SiMay.ReflectCache; +using System; using System.Collections.Generic; using System.Linq; using System.Text; namespace SiMay.Core.Packets.Reg { - public class RegValuesPack : BasePacket + public class RegValuesPack : EntitySerializerBase { public RegValueItem[] Values { get; set; } } diff --git a/SiMay.Core/Packets/RegEdit/DoChangeRegistryValuePack.cs b/SiMay.Core/Packets/RegEdit/DoChangeRegistryValuePack.cs index 4e6a719..e8bf599 100644 --- a/SiMay.Core/Packets/RegEdit/DoChangeRegistryValuePack.cs +++ b/SiMay.Core/Packets/RegEdit/DoChangeRegistryValuePack.cs @@ -1,11 +1,12 @@ -using System; +using SiMay.ReflectCache; +using System; using System.Collections.Generic; using System.Linq; using System.Text; namespace SiMay.Core.Packets.RegEdit { - public class DoChangeRegistryValuePack + public class DoChangeRegistryValuePack : EntitySerializerBase { public string KeyPath { get; set; } diff --git a/SiMay.Core/Packets/RegEdit/DoCreateRegistryKeyPack.cs b/SiMay.Core/Packets/RegEdit/DoCreateRegistryKeyPack.cs index f4cecf5..a072f2b 100644 --- a/SiMay.Core/Packets/RegEdit/DoCreateRegistryKeyPack.cs +++ b/SiMay.Core/Packets/RegEdit/DoCreateRegistryKeyPack.cs @@ -1,11 +1,12 @@ -using System; +using SiMay.ReflectCache; +using System; using System.Collections.Generic; using System.Linq; using System.Text; namespace SiMay.Core.Packets.RegEdit { - public class DoCreateRegistryKeyPack + public class DoCreateRegistryKeyPack : EntitySerializerBase { public string ParentPath { get; set; } } diff --git a/SiMay.Core/Packets/RegEdit/DoCreateRegistryValuePack.cs b/SiMay.Core/Packets/RegEdit/DoCreateRegistryValuePack.cs index d6b0b6f..028d8c9 100644 --- a/SiMay.Core/Packets/RegEdit/DoCreateRegistryValuePack.cs +++ b/SiMay.Core/Packets/RegEdit/DoCreateRegistryValuePack.cs @@ -1,4 +1,5 @@ using Microsoft.Win32; +using SiMay.ReflectCache; using System; using System.Collections.Generic; using System.Linq; @@ -6,7 +7,7 @@ using System.Text; namespace SiMay.Core.Packets.RegEdit { - public class DoCreateRegistryValuePack + public class DoCreateRegistryValuePack : EntitySerializerBase { public string KeyPath { get; set; } diff --git a/SiMay.Core/Packets/RegEdit/DoDeleteRegistryKeyPack.cs b/SiMay.Core/Packets/RegEdit/DoDeleteRegistryKeyPack.cs index 1273671..4ac2e16 100644 --- a/SiMay.Core/Packets/RegEdit/DoDeleteRegistryKeyPack.cs +++ b/SiMay.Core/Packets/RegEdit/DoDeleteRegistryKeyPack.cs @@ -1,11 +1,12 @@ -using System; +using SiMay.ReflectCache; +using System; using System.Collections.Generic; using System.Linq; using System.Text; namespace SiMay.Core.Packets.RegEdit { - public class DoDeleteRegistryKeyPack + public class DoDeleteRegistryKeyPack : EntitySerializerBase { public string ParentPath { get; set; } diff --git a/SiMay.Core/Packets/RegEdit/DoDeleteRegistryValuePack.cs b/SiMay.Core/Packets/RegEdit/DoDeleteRegistryValuePack.cs index 6148ba2..940f654 100644 --- a/SiMay.Core/Packets/RegEdit/DoDeleteRegistryValuePack.cs +++ b/SiMay.Core/Packets/RegEdit/DoDeleteRegistryValuePack.cs @@ -1,11 +1,12 @@ -using System; +using SiMay.ReflectCache; +using System; using System.Collections.Generic; using System.Linq; using System.Text; namespace SiMay.Core.Packets.RegEdit { - public class DoDeleteRegistryValuePack + public class DoDeleteRegistryValuePack : EntitySerializerBase { public string KeyPath { get; set; } diff --git a/SiMay.Core/Packets/RegEdit/DoLoadRegistryKeyPack.cs b/SiMay.Core/Packets/RegEdit/DoLoadRegistryKeyPack.cs index c979970..264501f 100644 --- a/SiMay.Core/Packets/RegEdit/DoLoadRegistryKeyPack.cs +++ b/SiMay.Core/Packets/RegEdit/DoLoadRegistryKeyPack.cs @@ -1,11 +1,12 @@ -using System; +using SiMay.ReflectCache; +using System; using System.Collections.Generic; using System.Linq; using System.Text; namespace SiMay.Core.Packets.RegEdit { - public class DoLoadRegistryKeyPack + public class DoLoadRegistryKeyPack : EntitySerializerBase { public string RootKeyName { get; set; } } diff --git a/SiMay.Core/Packets/RegEdit/DoRenameRegistryKeyPack.cs b/SiMay.Core/Packets/RegEdit/DoRenameRegistryKeyPack.cs index b31a566..aca263e 100644 --- a/SiMay.Core/Packets/RegEdit/DoRenameRegistryKeyPack.cs +++ b/SiMay.Core/Packets/RegEdit/DoRenameRegistryKeyPack.cs @@ -1,11 +1,12 @@ -using System; +using SiMay.ReflectCache; +using System; using System.Collections.Generic; using System.Linq; using System.Text; namespace SiMay.Core.Packets.RegEdit { - public class DoRenameRegistryKeyPack + public class DoRenameRegistryKeyPack : EntitySerializerBase { public string ParentPath { get; set; } diff --git a/SiMay.Core/Packets/RegEdit/DoRenameRegistryValuePack.cs b/SiMay.Core/Packets/RegEdit/DoRenameRegistryValuePack.cs index 49d22f2..b4153cf 100644 --- a/SiMay.Core/Packets/RegEdit/DoRenameRegistryValuePack.cs +++ b/SiMay.Core/Packets/RegEdit/DoRenameRegistryValuePack.cs @@ -1,11 +1,12 @@ -using System; +using SiMay.ReflectCache; +using System; using System.Collections.Generic; using System.Linq; using System.Text; namespace SiMay.Core.Packets.RegEdit { - public class DoRenameRegistryValuePack + public class DoRenameRegistryValuePack : EntitySerializerBase { public string KeyPath { get; set; } diff --git a/SiMay.Core/Packets/RegEdit/GetChangeRegistryValueResponsePack.cs b/SiMay.Core/Packets/RegEdit/GetChangeRegistryValueResponsePack.cs index ec3dbd9..a9a59ac 100644 --- a/SiMay.Core/Packets/RegEdit/GetChangeRegistryValueResponsePack.cs +++ b/SiMay.Core/Packets/RegEdit/GetChangeRegistryValueResponsePack.cs @@ -1,11 +1,12 @@ -using System; +using SiMay.ReflectCache; +using System; using System.Collections.Generic; using System.Linq; using System.Text; namespace SiMay.Core.Packets.RegEdit { - public class GetChangeRegistryValueResponsePack + public class GetChangeRegistryValueResponsePack : EntitySerializerBase { public string KeyPath { get; set; } diff --git a/SiMay.Core/Packets/RegEdit/GetCreateRegistryKeyResponsePack.cs b/SiMay.Core/Packets/RegEdit/GetCreateRegistryKeyResponsePack.cs index dbd5e50..ebdd6a2 100644 --- a/SiMay.Core/Packets/RegEdit/GetCreateRegistryKeyResponsePack.cs +++ b/SiMay.Core/Packets/RegEdit/GetCreateRegistryKeyResponsePack.cs @@ -1,11 +1,12 @@ -using System; +using SiMay.ReflectCache; +using System; using System.Collections.Generic; using System.Linq; using System.Text; namespace SiMay.Core.Packets.RegEdit { - public class GetCreateRegistryKeyResponsePack + public class GetCreateRegistryKeyResponsePack : EntitySerializerBase { public string ParentPath { get; set; } diff --git a/SiMay.Core/Packets/RegEdit/GetCreateRegistryValueResponsePack.cs b/SiMay.Core/Packets/RegEdit/GetCreateRegistryValueResponsePack.cs index b5d4a3a..3a75456 100644 --- a/SiMay.Core/Packets/RegEdit/GetCreateRegistryValueResponsePack.cs +++ b/SiMay.Core/Packets/RegEdit/GetCreateRegistryValueResponsePack.cs @@ -1,11 +1,12 @@ -using System; +using SiMay.ReflectCache; +using System; using System.Collections.Generic; using System.Linq; using System.Text; namespace SiMay.Core.Packets.RegEdit { - public class GetCreateRegistryValueResponsePack + public class GetCreateRegistryValueResponsePack : EntitySerializerBase { public string KeyPath { get; set; } diff --git a/SiMay.Core/Packets/RegEdit/GetDeleteRegistryKeyResponsePack.cs b/SiMay.Core/Packets/RegEdit/GetDeleteRegistryKeyResponsePack.cs index e943e5c..b01da19 100644 --- a/SiMay.Core/Packets/RegEdit/GetDeleteRegistryKeyResponsePack.cs +++ b/SiMay.Core/Packets/RegEdit/GetDeleteRegistryKeyResponsePack.cs @@ -1,11 +1,12 @@ -using System; +using SiMay.ReflectCache; +using System; using System.Collections.Generic; using System.Linq; using System.Text; namespace SiMay.Core.Packets.RegEdit { - public class GetDeleteRegistryKeyResponsePack + public class GetDeleteRegistryKeyResponsePack : EntitySerializerBase { public string ParentPath { get; set; } diff --git a/SiMay.Core/Packets/RegEdit/GetDeleteRegistryValueResponsePack.cs b/SiMay.Core/Packets/RegEdit/GetDeleteRegistryValueResponsePack.cs index 8b79578..a5a9135 100644 --- a/SiMay.Core/Packets/RegEdit/GetDeleteRegistryValueResponsePack.cs +++ b/SiMay.Core/Packets/RegEdit/GetDeleteRegistryValueResponsePack.cs @@ -1,11 +1,12 @@ -using System; +using SiMay.ReflectCache; +using System; using System.Collections.Generic; using System.Linq; using System.Text; namespace SiMay.Core.Packets.RegEdit { - public class GetDeleteRegistryValueResponsePack + public class GetDeleteRegistryValueResponsePack : EntitySerializerBase { public string KeyPath { get; set; } diff --git a/SiMay.Core/Packets/RegEdit/GetRegistryKeysResponsePack.cs b/SiMay.Core/Packets/RegEdit/GetRegistryKeysResponsePack.cs index eb4a067..ab3d816 100644 --- a/SiMay.Core/Packets/RegEdit/GetRegistryKeysResponsePack.cs +++ b/SiMay.Core/Packets/RegEdit/GetRegistryKeysResponsePack.cs @@ -1,11 +1,12 @@ -using System; +using SiMay.ReflectCache; +using System; using System.Collections.Generic; using System.Linq; using System.Text; namespace SiMay.Core.Packets.RegEdit { - public class GetRegistryKeysResponsePack + public class GetRegistryKeysResponsePack : EntitySerializerBase { public RegSeekerMatch[] Matches { get; set; } diff --git a/SiMay.Core/Packets/RegEdit/GetRenameRegistryKeyResponsePack.cs b/SiMay.Core/Packets/RegEdit/GetRenameRegistryKeyResponsePack.cs index 2fe7ee5..77b0c84 100644 --- a/SiMay.Core/Packets/RegEdit/GetRenameRegistryKeyResponsePack.cs +++ b/SiMay.Core/Packets/RegEdit/GetRenameRegistryKeyResponsePack.cs @@ -1,11 +1,12 @@ -using System; +using SiMay.ReflectCache; +using System; using System.Collections.Generic; using System.Linq; using System.Text; namespace SiMay.Core.Packets.RegEdit { - public class GetRenameRegistryKeyResponsePack + public class GetRenameRegistryKeyResponsePack : EntitySerializerBase { public string ParentPath { get; set; } diff --git a/SiMay.Core/Packets/RegEdit/GetRenameRegistryValueResponsePack.cs b/SiMay.Core/Packets/RegEdit/GetRenameRegistryValueResponsePack.cs index 80e2809..6dc1bd6 100644 --- a/SiMay.Core/Packets/RegEdit/GetRenameRegistryValueResponsePack.cs +++ b/SiMay.Core/Packets/RegEdit/GetRenameRegistryValueResponsePack.cs @@ -1,11 +1,12 @@ -using System; +using SiMay.ReflectCache; +using System; using System.Collections.Generic; using System.Linq; using System.Text; namespace SiMay.Core.Packets.RegEdit { - public class GetRenameRegistryValueResponsePack + public class GetRenameRegistryValueResponsePack : EntitySerializerBase { public string KeyPath { get; set; } diff --git a/SiMay.Core/Packets/RegEdit/RegSeekerMatch.cs b/SiMay.Core/Packets/RegEdit/RegSeekerMatch.cs index ae001f3..28ba8bf 100644 --- a/SiMay.Core/Packets/RegEdit/RegSeekerMatch.cs +++ b/SiMay.Core/Packets/RegEdit/RegSeekerMatch.cs @@ -1,11 +1,12 @@ -using System; +using SiMay.ReflectCache; +using System; using System.Collections.Generic; using System.Linq; using System.Text; namespace SiMay.Core.Packets.RegEdit { - public class RegSeekerMatch + public class RegSeekerMatch : EntitySerializerBase { public string Key { get; set; } diff --git a/SiMay.Core/Packets/RegEdit/RegValueData.cs b/SiMay.Core/Packets/RegEdit/RegValueData.cs index 0a73773..c209c03 100644 --- a/SiMay.Core/Packets/RegEdit/RegValueData.cs +++ b/SiMay.Core/Packets/RegEdit/RegValueData.cs @@ -1,4 +1,5 @@ using Microsoft.Win32; +using SiMay.ReflectCache; using System; using System.Collections.Generic; using System.Linq; @@ -6,7 +7,7 @@ using System.Text; namespace SiMay.Core.Packets.RegEdit { - public class RegValueData + public class RegValueData : EntitySerializerBase { public string Name { get; set; } diff --git a/SiMay.Core/Packets/RemoteUpdatePack.cs b/SiMay.Core/Packets/RemoteUpdatePack.cs index b6215a7..9d9f345 100644 --- a/SiMay.Core/Packets/RemoteUpdatePack.cs +++ b/SiMay.Core/Packets/RemoteUpdatePack.cs @@ -1,4 +1,5 @@ using SiMay.Core.Enums; +using SiMay.ReflectCache; using System; using System.Collections.Generic; using System.Linq; @@ -6,7 +7,7 @@ using System.Text; namespace SiMay.Core.Packets { - public class RemoteUpdatePack + public class RemoteUpdatePack : EntitySerializerBase { /// /// Url更新还是文件更新 diff --git a/SiMay.Core/Packets/Screen/MonitorChangePack.cs b/SiMay.Core/Packets/Screen/MonitorChangePack.cs index b0f5339..79f448b 100644 --- a/SiMay.Core/Packets/Screen/MonitorChangePack.cs +++ b/SiMay.Core/Packets/Screen/MonitorChangePack.cs @@ -1,11 +1,12 @@ -using System; +using SiMay.ReflectCache; +using System; using System.Collections.Generic; using System.Linq; using System.Text; namespace SiMay.Core.Packets.Screen { - public class MonitorChangePack + public class MonitorChangePack : EntitySerializerBase { public int MonitorIndex { get; set; } } diff --git a/SiMay.Core/Packets/Screen/ScreenBitInfoPack.cs b/SiMay.Core/Packets/Screen/ScreenBitInfoPack.cs index aad526e..f684491 100644 --- a/SiMay.Core/Packets/Screen/ScreenBitInfoPack.cs +++ b/SiMay.Core/Packets/Screen/ScreenBitInfoPack.cs @@ -1,11 +1,12 @@ -using System; +using SiMay.ReflectCache; +using System; using System.Collections.Generic; using System.Linq; using System.Text; namespace SiMay.Core.Packets { - public class ScreenInitBitPack : BasePacket + public class ScreenInitBitPack : EntitySerializerBase { public int Height { get; set; } public int Width { get; set; } @@ -14,7 +15,7 @@ namespace SiMay.Core.Packets public MonitorItem[] Monitors { get; set; } } - public class MonitorItem + public class MonitorItem : EntitySerializerBase { public string DeviceName { get; set; } public bool Primary { get; set; } diff --git a/SiMay.Core/Packets/Screen/ScreenClipoardValuePack.cs b/SiMay.Core/Packets/Screen/ScreenClipoardValuePack.cs index 9143579..8956bbd 100644 --- a/SiMay.Core/Packets/Screen/ScreenClipoardValuePack.cs +++ b/SiMay.Core/Packets/Screen/ScreenClipoardValuePack.cs @@ -1,11 +1,12 @@ -using System; +using SiMay.ReflectCache; +using System; using System.Collections.Generic; using System.Linq; using System.Text; namespace SiMay.Core.Packets.Screen { - public class ScreenClipoardValuePack : BasePacket + public class ScreenClipoardValuePack : EntitySerializerBase { public string Value { get; set; } } diff --git a/SiMay.Core/Packets/Screen/ScreenFragmentPack.cs b/SiMay.Core/Packets/Screen/ScreenFragmentPack.cs index 3bf7613..be581e8 100644 --- a/SiMay.Core/Packets/Screen/ScreenFragmentPack.cs +++ b/SiMay.Core/Packets/Screen/ScreenFragmentPack.cs @@ -1,4 +1,5 @@ using SiMay.Core.ScreenSpy.Entitys; +using SiMay.ReflectCache; using System; using System.Collections.Generic; using System.Linq; @@ -6,7 +7,7 @@ using System.Text; namespace SiMay.Core.Packets { - public class ScreenFragmentPack : BasePacket + public class ScreenFragmentPack : EntitySerializerBase { public Fragment[] Fragments { get; set; } } diff --git a/SiMay.Core/Packets/Screen/ScreenHotRectanglePack.cs b/SiMay.Core/Packets/Screen/ScreenHotRectanglePack.cs index d017499..a224059 100644 --- a/SiMay.Core/Packets/Screen/ScreenHotRectanglePack.cs +++ b/SiMay.Core/Packets/Screen/ScreenHotRectanglePack.cs @@ -1,11 +1,12 @@ -using System; +using SiMay.ReflectCache; +using System; using System.Collections.Generic; using System.Linq; using System.Text; namespace SiMay.Core.Packets { - public class ScreenHotRectanglePack : BasePacket + public class ScreenHotRectanglePack : EntitySerializerBase { public int X { get; set; } public int Y { get; set; } diff --git a/SiMay.Core/Packets/Screen/ScreenMKeyPack.cs b/SiMay.Core/Packets/Screen/ScreenKeyPack.cs similarity index 78% rename from SiMay.Core/Packets/Screen/ScreenMKeyPack.cs rename to SiMay.Core/Packets/Screen/ScreenKeyPack.cs index e188a12..e96af76 100644 --- a/SiMay.Core/Packets/Screen/ScreenMKeyPack.cs +++ b/SiMay.Core/Packets/Screen/ScreenKeyPack.cs @@ -1,4 +1,5 @@ using SiMay.Core.Enums; +using SiMay.ReflectCache; using System; using System.Collections.Generic; using System.Linq; @@ -6,7 +7,7 @@ using System.Text; namespace SiMay.Core.Packets { - public class ScreenMKeyPack : BasePacket + public class ScreenKeyPack : EntitySerializerBase { public MOUSEKEY_ENUM Key { get; set; } public int Point1 { get; set; } diff --git a/SiMay.Core/Packets/Screen/ScreenSetClipoardPack.cs b/SiMay.Core/Packets/Screen/ScreenSetClipoardPack.cs index 818116b..bcf5252 100644 --- a/SiMay.Core/Packets/Screen/ScreenSetClipoardPack.cs +++ b/SiMay.Core/Packets/Screen/ScreenSetClipoardPack.cs @@ -1,11 +1,12 @@ -using System; +using SiMay.ReflectCache; +using System; using System.Collections.Generic; using System.Linq; using System.Text; namespace SiMay.Core.Packets.Screen { - public class ScreenSetClipoardPack : BasePacket + public class ScreenSetClipoardPack : EntitySerializerBase { public string Text { get; set; } } diff --git a/SiMay.Core/Packets/Screen/ScreenSetQtyPack.cs b/SiMay.Core/Packets/Screen/ScreenSetQtyPack.cs index 0752b49..42a5f64 100644 --- a/SiMay.Core/Packets/Screen/ScreenSetQtyPack.cs +++ b/SiMay.Core/Packets/Screen/ScreenSetQtyPack.cs @@ -1,11 +1,12 @@ -using System; +using SiMay.ReflectCache; +using System; using System.Collections.Generic; using System.Linq; using System.Text; namespace SiMay.Core.Packets.Screen { - public class ScreenSetQtyPack + public class ScreenSetQtyPack : EntitySerializerBase { public long Quality { get; set; } } diff --git a/SiMay.Core/Packets/ServicePluginPack.cs b/SiMay.Core/Packets/ServicePluginPack.cs index 6b4a0eb..d7cae56 100644 --- a/SiMay.Core/Packets/ServicePluginPack.cs +++ b/SiMay.Core/Packets/ServicePluginPack.cs @@ -1,16 +1,17 @@ -using System; +using SiMay.ReflectCache; +using System; using System.Collections.Generic; using System.Linq; using System.Text; namespace SiMay.Core.Packets { - public class ServicePluginPack + public class ServicePluginPack : EntitySerializerBase { public PluginItem[] Files { get; set; } } - public class PluginItem + public class PluginItem : EntitySerializerBase { public string FileName { get; set; } public byte[] PayLoad { get; set; } diff --git a/SiMay.Core/Packets/Startup/StartupItemPack.cs b/SiMay.Core/Packets/Startup/StartupItemPack.cs index 49b9f7a..846cd82 100644 --- a/SiMay.Core/Packets/Startup/StartupItemPack.cs +++ b/SiMay.Core/Packets/Startup/StartupItemPack.cs @@ -1,4 +1,5 @@ using SiMay.Core.Enums; +using SiMay.ReflectCache; using System; using System.Collections.Generic; using System.Linq; @@ -6,11 +7,11 @@ using System.Text; namespace SiMay.Core.Packets.Startup { - public class StartupItemsPack : BasePacket + public class StartupItemsPack : EntitySerializerBase { public StartupItemPack[] StartupItems { get; set; } } - public class StartupItemPack : BasePacket + public class StartupItemPack : EntitySerializerBase { public string Name { get; set; } diff --git a/SiMay.Core/Packets/Startup/StartupOperResponsePack.cs b/SiMay.Core/Packets/Startup/StartupOperResponsePack.cs index 4b29b35..147ff97 100644 --- a/SiMay.Core/Packets/Startup/StartupOperResponsePack.cs +++ b/SiMay.Core/Packets/Startup/StartupOperResponsePack.cs @@ -1,4 +1,5 @@ using SiMay.Core.Packets.Startup.Enums; +using SiMay.ReflectCache; using System; using System.Collections.Generic; using System.Linq; @@ -6,7 +7,7 @@ using System.Text; namespace SiMay.Core.Packets.Startup { - public class StartupOperResponsePack : BasePacket + public class StartupOperResponsePack : EntitySerializerBase { public OperFlag OperFlag { get; set; } public string Msg { get; set; } diff --git a/SiMay.Core/Packets/SysManager/ProcessInfo.cs b/SiMay.Core/Packets/SysManager/ProcessInfo.cs index 06705a3..5d93b75 100644 --- a/SiMay.Core/Packets/SysManager/ProcessInfo.cs +++ b/SiMay.Core/Packets/SysManager/ProcessInfo.cs @@ -1,11 +1,12 @@ -using System; +using SiMay.ReflectCache; +using System; using System.Collections.Generic; using System.Linq; using System.Text; namespace SiMay.Core.Packets { - public class ProcessItem + public class ProcessItem : EntitySerializerBase { public int ProcessId { get; set; } diff --git a/SiMay.Core/Packets/SysManager/SessionManagerPack.cs b/SiMay.Core/Packets/SysManager/SessionManagerPack.cs index 0d5ebc0..52ffc26 100644 --- a/SiMay.Core/Packets/SysManager/SessionManagerPack.cs +++ b/SiMay.Core/Packets/SysManager/SessionManagerPack.cs @@ -1,21 +1,22 @@ -using System; +using SiMay.ReflectCache; +using System; using System.Collections.Generic; using System.Linq; using System.Text; namespace SiMay.Core.Packets.SysManager { - public class CreateProcessAsUserPack + public class CreateProcessAsUserPack : EntitySerializerBase { public int SessionId { get; set; } } - public class SessionsPack : BasePacket + public class SessionsPack : EntitySerializerBase { public SessionItem[] Sessions { get; set; } } - public class SessionItem + public class SessionItem : EntitySerializerBase { public string UserName { get; set; } public int SessionId { get; set; } diff --git a/SiMay.Core/Packets/SysManager/SysKillPack.cs b/SiMay.Core/Packets/SysManager/SysKillPack.cs index 3de9227..4bee48f 100644 --- a/SiMay.Core/Packets/SysManager/SysKillPack.cs +++ b/SiMay.Core/Packets/SysManager/SysKillPack.cs @@ -1,11 +1,12 @@ -using System; +using SiMay.ReflectCache; +using System; using System.Collections.Generic; using System.Linq; using System.Text; namespace SiMay.Core.Packets.SysManager { - public class SysKillPack : BasePacket + public class SysKillPack : EntitySerializerBase { public int[] ProcessIds { get; set; } } diff --git a/SiMay.Core/Packets/SysManager/SysWindowMaxPack.cs b/SiMay.Core/Packets/SysManager/SysWindowMaxPack.cs index 8ce4523..c115f39 100644 --- a/SiMay.Core/Packets/SysManager/SysWindowMaxPack.cs +++ b/SiMay.Core/Packets/SysManager/SysWindowMaxPack.cs @@ -1,11 +1,12 @@ -using System; +using SiMay.ReflectCache; +using System; using System.Collections.Generic; using System.Linq; using System.Text; namespace SiMay.Core.Packets.SysManager { - public class SysWindowMaxPack : BasePacket + public class SysWindowMaxPack : EntitySerializerBase { public int State { get; set; } public int[] Handlers { get; set; } diff --git a/SiMay.Core/Packets/SysManager/SystemInfoPack.cs b/SiMay.Core/Packets/SysManager/SystemInfoPack.cs index d8fa42e..4028553 100644 --- a/SiMay.Core/Packets/SysManager/SystemInfoPack.cs +++ b/SiMay.Core/Packets/SysManager/SystemInfoPack.cs @@ -1,26 +1,27 @@ -using System; +using SiMay.ReflectCache; +using System; using System.Collections.Generic; using System.Linq; using System.Text; namespace SiMay.Core.Packets { - public class ProcessListPack : BasePacket + public class ProcessListPack : EntitySerializerBase { public ProcessItem[] ProcessList { get; set; } } - public class SystemInfoPack : BasePacket + public class SystemInfoPack : EntitySerializerBase { public SystemInfoItem[] SystemInfos { get; set; } } - public class SystemOccupyPack : BasePacket + public class SystemOccupyPack : EntitySerializerBase { public string CpuUsage { get; set; } public string MemoryUsage { get; set; } } - public class SystemInfoItem + public class SystemInfoItem : EntitySerializerBase { public string ItemName { get; set; } public string Value { get; set; } diff --git a/SiMay.Core/Packets/TcpConnection/TcpConnectionItem.cs b/SiMay.Core/Packets/TcpConnection/TcpConnectionItem.cs index 5bf5348..f67ce3b 100644 --- a/SiMay.Core/Packets/TcpConnection/TcpConnectionItem.cs +++ b/SiMay.Core/Packets/TcpConnection/TcpConnectionItem.cs @@ -3,10 +3,11 @@ using System.Collections.Generic; using System.Linq; using System.Text; using SiMay.Core.Enums; +using SiMay.ReflectCache; namespace SiMay.Core.Packets.TcpConnection { - public class TcpConnectionItem + public class TcpConnectionItem : EntitySerializerBase { public string ProcessName { get; set; } public string LocalAddress { get; set; } diff --git a/SiMay.Core/Packets/TcpConnection/TcpConnectionPack.cs b/SiMay.Core/Packets/TcpConnection/TcpConnectionPack.cs index 4d38354..90ff7df 100644 --- a/SiMay.Core/Packets/TcpConnection/TcpConnectionPack.cs +++ b/SiMay.Core/Packets/TcpConnection/TcpConnectionPack.cs @@ -1,20 +1,21 @@ -using System; +using SiMay.ReflectCache; +using System; using System.Collections.Generic; using System.Linq; using System.Text; namespace SiMay.Core.Packets.TcpConnection { - public class TcpConnectionPack : BasePacket + public class TcpConnectionPack : EntitySerializerBase { public TcpConnectionItem[] TcpConnections { get; set; } } - public class KillTcpConnectionPack : BasePacket + public class KillTcpConnectionPack : EntitySerializerBase { public KillTcpConnectionItem[] Kills { get; set; } } - public class KillTcpConnectionItem + public class KillTcpConnectionItem : EntitySerializerBase { public string LocalAddress { get; set; } diff --git a/SiMay.Core/SiMay.Core.csproj b/SiMay.Core/SiMay.Core.csproj index 797bfae..819fe7c 100644 --- a/SiMay.Core/SiMay.Core.csproj +++ b/SiMay.Core/SiMay.Core.csproj @@ -9,7 +9,7 @@ Properties SiMay.Core SiMay.Core - v4.0 + v4.6.1 512 @@ -23,6 +23,7 @@ 4 true 8.0 + false pdbonly @@ -33,6 +34,7 @@ 4 true 8.0 + false @@ -49,7 +51,7 @@ - + @@ -69,7 +71,7 @@ - + @@ -98,7 +100,7 @@ - + @@ -133,7 +135,7 @@ - + @@ -148,7 +150,6 @@ - @@ -169,10 +170,6 @@ {4888d6bb-46d9-4519-8758-e13e397aa226} SiMay.Serialize - - {d181fcce-ecc7-4710-89cc-d97f94a6181b} - SiMay.Sockets.V4 - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - text/microsoft-resx - - - 2.0 - - - System.Resources.ResXResourceReader, System.Windows.Forms, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 - - - System.Resources.ResXResourceWriter, System.Windows.Forms, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 - - \ No newline at end of file diff --git a/SiMay.UpdateClient/Properties/Settings.Designer.cs b/SiMay.UpdateClient/Properties/Settings.Designer.cs deleted file mode 100644 index b2953e2..0000000 --- a/SiMay.UpdateClient/Properties/Settings.Designer.cs +++ /dev/null @@ -1,30 +0,0 @@ -//------------------------------------------------------------------------------ -// -// This code was generated by a tool. -// Runtime Version:4.0.30319.42000 -// -// Changes to this file may cause incorrect behavior and will be lost if -// the code is regenerated. -// -//------------------------------------------------------------------------------ - -namespace SiMay.UpdateClient.Properties -{ - - - [global::System.Runtime.CompilerServices.CompilerGeneratedAttribute()] - [global::System.CodeDom.Compiler.GeneratedCodeAttribute("Microsoft.VisualStudio.Editors.SettingsDesigner.SettingsSingleFileGenerator", "11.0.0.0")] - internal sealed partial class Settings : global::System.Configuration.ApplicationSettingsBase - { - - private static Settings defaultInstance = ((Settings)(global::System.Configuration.ApplicationSettingsBase.Synchronized(new Settings()))); - - public static Settings Default - { - get - { - return defaultInstance; - } - } - } -} diff --git a/SiMay.UpdateClient/Properties/Settings.settings b/SiMay.UpdateClient/Properties/Settings.settings deleted file mode 100644 index 3964565..0000000 --- a/SiMay.UpdateClient/Properties/Settings.settings +++ /dev/null @@ -1,7 +0,0 @@ - - - - - - - diff --git a/SiMay.UpdateClient/SiMay.UpdateClient.csproj b/SiMay.UpdateClient/SiMay.UpdateClient.csproj deleted file mode 100644 index a8a9cd8..0000000 --- a/SiMay.UpdateClient/SiMay.UpdateClient.csproj +++ /dev/null @@ -1,69 +0,0 @@ - - - - - Debug - AnyCPU - {76E07A4F-8839-4260-925A-3179DB1C6045} - WinExe - SiMay.UpdateClient - SiMay.UpdateClient - v4.0 - 512 - - - AnyCPU - true - full - false - bin\Debug\ - DEBUG;TRACE - prompt - 4 - - - AnyCPU - pdbonly - true - bin\Release\ - TRACE - prompt - 4 - - - - - - - - - - - - - - - - - - ResXFileCodeGenerator - Resources.Designer.cs - Designer - - - True - Resources.resx - - - SettingsSingleFileGenerator - Settings.Designer.cs - - - True - Settings.settings - True - - - - - \ No newline at end of file diff --git a/SiMay.UpdateClient/SiMaySeriver.NewCore.mm b/SiMay.UpdateClient/SiMaySeriver.NewCore.mm deleted file mode 100644 index a21b725e69ce35951eb7544cde51cb16aad0b9a2..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 178176 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

!B6~e$Y<}7r+&0?yFi!#w$SLo`b*0cL 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

GiqhN(-pKp5i_ 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 + + + + + diff --git a/SiMaySerializeTestApp2/Program.cs b/SiMaySerializeTestApp2/Program.cs new file mode 100644 index 0000000..0720117 --- /dev/null +++ b/SiMaySerializeTestApp2/Program.cs @@ -0,0 +1,83 @@ +using SiMay.Serialize; +using System; +using System.Collections.Generic; +using System.Diagnostics; +using System.Linq; +using System.Text; + +namespace SiMaySerializeTestApp +{ + class Program + { + public class TestB + { + public bool[] isArray { get; set; } + public bool isSuccess { get; set; } + public byte[] Data { get; set; } + public int Id { get; set; } + } + public class TestA + { + public int Id { get; set; } + public int[] Ids { get; set; } + public string Name { get; set; } + public string[] Names { get; set; } + public TestB B { get; set; } + public TestA[] As { get; set; } + public DateTime Time { get; set; } + public MyEnum MyEnum { get; set; } + public double[] bs { get; set; } = new double[] { 123, 132 }; + } + public enum MyEnum + { + A, B, C + } + static void Main(string[] args) + { + List list = new List(); + for (int i = 0; i < 5; i++) + { + TestA a = new TestA() + { + Id = 12313213 + i, + Ids = new int[] { 1213, 11, 1 }, + Name = "哈哈哈", + Names = new string[] { "嘿嘿", "AAA" }, + B = new TestB() + { + isSuccess = true, + Id = 12132132 + i, + Data = new byte[] { 1, 2, 255 } + }, + As = new TestA[] { }, + Time = DateTime.Now + }; + list.Add(a); + } + TestA A = new TestA() + { + Id = 123, + Ids = null, + Name = null, + Names = null, + B = null, + As = list.ToArray(), + //Time = DateTime.Now, + MyEnum = MyEnum.B + }; + + Stopwatch sw = new Stopwatch(); + sw.Start(); + var bytes = PacketSerializeHelper.SerializePacket(A); + sw.Stop(); + Console.WriteLine("序列化耗时:" + sw.Elapsed.TotalSeconds); + sw.Reset(); + sw.Start(); + TestA pack = PacketSerializeHelper.DeserializePacket(bytes); + sw.Stop(); + Console.WriteLine("反序列化耗时:" + sw.Elapsed.TotalSeconds); + + Console.Read(); + } + } +} diff --git a/SiMay.Sockets.V4/Properties/AssemblyInfo.cs b/SiMaySerializeTestApp2/Properties/AssemblyInfo.cs similarity index 76% rename from SiMay.Sockets.V4/Properties/AssemblyInfo.cs rename to SiMaySerializeTestApp2/Properties/AssemblyInfo.cs index 58fae0c..b43e369 100644 --- a/SiMay.Sockets.V4/Properties/AssemblyInfo.cs +++ b/SiMaySerializeTestApp2/Properties/AssemblyInfo.cs @@ -5,12 +5,12 @@ using System.Runtime.InteropServices; // 有关程序集的一般信息由以下 // 控制。更改这些特性值可修改 // 与程序集关联的信息。 -[assembly: AssemblyTitle("SiMay.Socket")] +[assembly: AssemblyTitle("SiMaySerializeTestApp2")] [assembly: AssemblyDescription("")] [assembly: AssemblyConfiguration("")] [assembly: AssemblyCompany("")] -[assembly: AssemblyProduct("SiMay.Socket")] -[assembly: AssemblyCopyright("Copyright © 2018")] +[assembly: AssemblyProduct("SiMaySerializeTestApp2")] +[assembly: AssemblyCopyright("Copyright © 2020")] [assembly: AssemblyTrademark("")] [assembly: AssemblyCulture("")] @@ -20,7 +20,7 @@ using System.Runtime.InteropServices; [assembly: ComVisible(false)] // 如果此项目向 COM 公开,则下列 GUID 用于类型库的 ID -[assembly: Guid("b0f8473c-10b8-4cf7-ae18-32037fa9bbae")] +[assembly: Guid("263a26f1-5235-4ea5-b2d6-adf219a07cd2")] // 程序集的版本信息由下列四个值组成: // @@ -29,7 +29,7 @@ using System.Runtime.InteropServices; // 生成号 // 修订号 // -// 可以指定所有值,也可以使用以下所示的 "*" 预置版本号和修订号 +//可以指定所有这些值,也可以使用“生成号”和“修订号”的默认值 //通过使用 "*",如下所示: // [assembly: AssemblyVersion("1.0.*")] [assembly: AssemblyVersion("1.0.0.0")] diff --git a/SiMay.Daemon/SiMay.Daemon.csproj b/SiMaySerializeTestApp2/SiMaySerializeTestApp2.csproj similarity index 70% rename from SiMay.Daemon/SiMay.Daemon.csproj rename to SiMaySerializeTestApp2/SiMaySerializeTestApp2.csproj index b5562a4..01f2d74 100644 --- a/SiMay.Daemon/SiMay.Daemon.csproj +++ b/SiMaySerializeTestApp2/SiMaySerializeTestApp2.csproj @@ -4,12 +4,14 @@ Debug AnyCPU - {77867DE2-193E-4533-B365-31CEF16A876B} - WinExe - SiMay.Daemon - SiMay.Daemon - v4.0 + {263A26F1-5235-4EA5-B2D6-ADF219A07CD2} + Exe + SiMaySerializeTestApp2 + SiMaySerializeTestApp2 + v4.5 512 + true + true @@ -17,7 +19,7 @@ true full false - ..\Bin\dat\ + bin\Debug\ DEBUG;TRACE prompt 4 @@ -32,23 +34,24 @@ 4 + + ..\SiMay.Serialize\SiMaySerializeTestApp\bin\Debug\SiMay.Serialize.dll + - + - + + - - - - + \ No newline at end of file -- Gitee From 2a16e43f8decb426940505b49ef240b45a30deb2 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E6=96=87=E7=8E=8B=E7=8E=8B?= <596461462@qq.com> Date: Wed, 12 Feb 2020 12:52:48 +0800 Subject: [PATCH 06/19] =?UTF-8?q?=E4=B8=AD=E9=97=B4=E6=9C=8D=E5=8A=A1?= =?UTF-8?q?=E9=87=8D=E6=9E=84(=E6=9C=AA=E5=AE=8C=E6=88=90)=EF=BC=8C?= =?UTF-8?q?=E7=B3=BB=E7=BB=9F=E4=BC=98=E5=8C=96?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- README.md | 89 ++++---- SiMay.Basic/GZipHelper.cs | 5 +- SiMay.Basic/Properties/AssemblyInfo.cs | 36 --- SiMay.Basic/RectangleHelper.cs | 2 +- SiMay.Basic/SiMay.Basic.csproj | 75 +------ SiMay.Core/Enums/ConnectionWorkType.cs | 17 +- SiMay.Core/Enums/DifferStatus.cs | 17 +- SiMay.Core/Enums/FileType.cs | 11 + SiMay.Core/Enums/MessageIcon.cs | 15 ++ SiMay.Core/Enums/MouseKeyEnum.cs | 32 +++ SiMay.Core/Enums/RemoteUpdateType.cs | 7 + SiMay.Core/Enums/SystemSessionType.cs | 35 +++ SiMay.Core/MessageHelper.cs | 2 +- SiMay.Core/ScreenSpy/ScreenSpy.cs | 6 +- SiMay.Core/SiMay.Core.csproj | 8 +- .../Entitys/AckPacket.cs | 15 ++ .../Entitys/LogOutPacket.cs | 15 ++ .../Entitys/MessageDataPacket.cs | 16 ++ .../Entitys/SessionClosedPacket.cs | 12 + .../Entitys/SessionPacket.cs | 19 ++ .../Enums/ConnectionWorkType.cs | 35 +++ .../Enums/MessageHead.cs | 55 +++++ .../Extension/UnicodeExtensions.cs | 19 ++ .../Helper/MessageHelper.cs | 105 +++++++++ .../SiMay.Net.SessionProvider.Core.csproj | 63 +----- .../Helper/MessageHelper.cs | 105 +++++++++ .../LogHelper.cs | 0 .../MsgCommand.cs | 0 .../Properties/AssemblyInfo.cs | 0 .../SiMay.Net.SessionProvider.Core.csproj | 19 +- .../Win32Api.cs | 0 SiMay.Net.SessionProvider/MessageHelper.cs | 2 +- .../Properties/AssemblyInfo.cs | 36 --- .../TcpProxySessionProviderHandle.cs | 21 +- .../SessionBased/TcpProxySessionBased.cs | 4 +- .../SiMay.Net.SessionProvider.csproj | 95 +------- .../SiMay.Net.SessionProvider.rar | Bin 91395 -> 0 bytes SiMay.Net.SessionProviderService/App.config | 2 +- .../Properties/Settings.Designer.cs | 2 +- .../SiMay.Net.SessionProviderService.csproj | 8 +- .../ApplicationConfiguartion.cs | 39 ++++ .../Dispatcher/ApportionDispatcher.cs | 127 +++++++++++ .../TcpSessionApplicationWorkerConnection.cs | 39 ++++ .../TcpSessionMainApplicationConnection.cs | 96 ++++++++ .../Dispatcher/TcpSessionMainConnection.cs | 84 +++++++ .../DispatcherBase/DispatcherBase.cs | 107 +++++++++ .../TcpSessionChannelDispatcher.cs | 14 ++ .../Extension/CreateDispatcherExtension.cs | 53 +++++ .../MainSessionProviderService.cs | 205 ++++++++++++++++++ ...iMay.Net.SessionProviderServiceCore.csproj | 14 ++ .../SysContanct.cs | 12 + .../ApplicationService/ScreenService.cs | 6 +- SiMay.RemoteClient.NewCore/Program.cs | 1 + .../ServiceBase/ApplicationProtocolService.cs | 2 +- .../SiMay.ServiceCore.csproj | 8 +- SiMay.RemoteClient.NewCore/SysUtil.cs | 2 +- .../RemoteFileAdapterHandler.cs | 12 +- .../RemoteScreenAdapterHandler.cs | 2 +- .../MainApplicationAdapterHandler.cs | 28 +-- .../SiMay.RemoteControlsCore.csproj | 10 +- SiMay.RemoteControlsCore/SysConstants.cs | 2 +- .../Application/FileApplication.cs | 31 +-- .../Application/ScreenApplication.cs | 2 +- .../Helper/ListViewSortHelper.cs | 2 +- .../Helper}/MessageBoxHelper.cs | 2 +- .../MainApplication/BuilderServiceForm.cs | 3 +- .../MainApplication/DesktopRecordForm.cs | 6 +- .../SiMay.RemoteMonitor.csproj | 11 +- .../PacketDeserializeSetup.cs | 2 +- .../PacketSerializeHelper.cs | 2 +- .../PacketSerializeSetup.cs | 2 +- .../DynamicMethodMemberAccessor.cs | 0 .../ReflectCachePool/EntitySerializerBase.cs | 0 .../ReflectCachePool/IMemberAccessor.cs | 0 .../SiMay.Serialize.Standard.csproj | 7 + SiMay.Serialize/Properties/AssemblyInfo.cs | 36 --- SiMay.Serialize/README.md | 0 SiMay.Serialize/SiMaySerialize.sln | 37 ---- .../SiMaySerializeTestApp/Program.cs | 85 -------- .../Properties/AssemblyInfo.cs | 36 --- .../SiMaySerializeTestApp.csproj | 54 ----- .../SiMay.Sockets.Standard.csproj | 4 + .../Tcp/Session/TcpSocketSaeaPackBased.cs | 4 +- .../Tcp/Session/TcpSocketSaeaSession.cs | 3 + .../{DeCompressHelper.cs => GZipHelper.cs} | 6 +- ...oteManager.sln => SiMayRemoteMonitorOS.sln | 135 +++++++----- 86 files changed, 1590 insertions(+), 748 deletions(-) delete mode 100644 SiMay.Basic/Properties/AssemblyInfo.cs create mode 100644 SiMay.Net.SessionProvider.Core/Entitys/AckPacket.cs create mode 100644 SiMay.Net.SessionProvider.Core/Entitys/LogOutPacket.cs create mode 100644 SiMay.Net.SessionProvider.Core/Entitys/MessageDataPacket.cs create mode 100644 SiMay.Net.SessionProvider.Core/Entitys/SessionClosedPacket.cs create mode 100644 SiMay.Net.SessionProvider.Core/Entitys/SessionPacket.cs create mode 100644 SiMay.Net.SessionProvider.Core/Enums/ConnectionWorkType.cs create mode 100644 SiMay.Net.SessionProvider.Core/Enums/MessageHead.cs create mode 100644 SiMay.Net.SessionProvider.Core/Extension/UnicodeExtensions.cs create mode 100644 SiMay.Net.SessionProvider.Core/Helper/MessageHelper.cs create mode 100644 SiMay.Net.SessionProvider.Core_/Helper/MessageHelper.cs rename {SiMay.Net.SessionProvider.Core => SiMay.Net.SessionProvider.Core_}/LogHelper.cs (100%) rename {SiMay.Net.SessionProvider.Core => SiMay.Net.SessionProvider.Core_}/MsgCommand.cs (100%) rename {SiMay.Net.SessionProvider.Core => SiMay.Net.SessionProvider.Core_}/Properties/AssemblyInfo.cs (100%) rename SiMay.Serialize/SiMay.Serialize.csproj => SiMay.Net.SessionProvider.Core_/SiMay.Net.SessionProvider.Core.csproj (78%) rename {SiMay.Net.SessionProvider.Core => SiMay.Net.SessionProvider.Core_}/Win32Api.cs (100%) delete mode 100644 SiMay.Net.SessionProvider/Properties/AssemblyInfo.cs delete mode 100644 SiMay.Net.SessionProvider/SiMay.Net.SessionProvider.rar create mode 100644 SiMay.Net.SessionProviderServiceCore/ApplicationConfiguartion.cs create mode 100644 SiMay.Net.SessionProviderServiceCore/Dispatcher/ApportionDispatcher.cs create mode 100644 SiMay.Net.SessionProviderServiceCore/Dispatcher/TcpSessionApplicationWorkerConnection.cs create mode 100644 SiMay.Net.SessionProviderServiceCore/Dispatcher/TcpSessionMainApplicationConnection.cs create mode 100644 SiMay.Net.SessionProviderServiceCore/Dispatcher/TcpSessionMainConnection.cs create mode 100644 SiMay.Net.SessionProviderServiceCore/DispatcherBase/DispatcherBase.cs create mode 100644 SiMay.Net.SessionProviderServiceCore/DispatcherBase/TcpSessionChannelDispatcher.cs create mode 100644 SiMay.Net.SessionProviderServiceCore/Extension/CreateDispatcherExtension.cs create mode 100644 SiMay.Net.SessionProviderServiceCore/MainSessionProviderService.cs create mode 100644 SiMay.Net.SessionProviderServiceCore/SiMay.Net.SessionProviderServiceCore.csproj create mode 100644 SiMay.Net.SessionProviderServiceCore/SysContanct.cs rename {SiMay.Basic => SiMay.RemoteMonitor/Helper}/MessageBoxHelper.cs (95%) rename {SiMay.Serialize => SiMay.Serialize.Standard}/PacketDeserializeSetup.cs (99%) rename {SiMay.Serialize => SiMay.Serialize.Standard}/PacketSerializeHelper.cs (94%) rename {SiMay.Serialize => SiMay.Serialize.Standard}/PacketSerializeSetup.cs (99%) rename {SiMay.Serialize => SiMay.Serialize.Standard}/ReflectCachePool/DynamicMethodMemberAccessor.cs (100%) rename {SiMay.Serialize => SiMay.Serialize.Standard}/ReflectCachePool/EntitySerializerBase.cs (100%) rename {SiMay.Serialize => SiMay.Serialize.Standard}/ReflectCachePool/IMemberAccessor.cs (100%) create mode 100644 SiMay.Serialize.Standard/SiMay.Serialize.Standard.csproj delete mode 100644 SiMay.Serialize/Properties/AssemblyInfo.cs delete mode 100644 SiMay.Serialize/README.md delete mode 100644 SiMay.Serialize/SiMaySerialize.sln delete mode 100644 SiMay.Serialize/SiMaySerializeTestApp/Program.cs delete mode 100644 SiMay.Serialize/SiMaySerializeTestApp/Properties/AssemblyInfo.cs delete mode 100644 SiMay.Serialize/SiMaySerializeTestApp/SiMaySerializeTestApp.csproj rename SiMay.Sockets.Standard/UtilityHelper/{DeCompressHelper.cs => GZipHelper.cs} (90%) rename SiMayRemoteManager.sln => SiMayRemoteMonitorOS.sln (68%) diff --git a/README.md b/README.md index eaecf03..b59bcf3 100644 --- a/README.md +++ b/README.md @@ -1,12 +1,11 @@ - -# 系统介绍 - - SiMay远程控制管理系统一套Windows远程控制系统,底层基于IOCP的异步通信模型,能对海量客户端实时监控,目前功能已实现了采用可视区域逐行扫描的远程桌面控制,只发送桌面变化区域,有效节省传输流量;经典的文件管理方式,支持快速上传下载文件和文件夹;语音监听实时传输远程语音,发送语音;视频监视采用Dx组件捕获视频画面,兼容市场主流摄像头;键盘监控全局Hook键盘,支持离线记录;经典的注册表管理;cmd终端;系统进程管理,桌面视图墙等功能,并且实现了中间会话服务器(测试阶段),支持Web端监控,项目完全采用C#.NET开发,代码仅供参考,项目不定时更新,欢迎关注点星星,fork。欢迎入群技术交流:905958449 :laughing: :blush: +# 系统介绍 + - SiMay远程控制管理系统是一个Windows远程控制系统,底层基于IOCP的异步通信模型,能对海量客户端实时监控,目前功能已实现:远程桌面,基于可视区域逐行扫描算法,仅传输桌面变化区域,可有效节省传输流量;经典的文件管理方式,实现了快速上传下载文件和文件夹;实时传输远程语音与发送语音,及实时捕获远程摄像头;Windows风格界面的经典注册表管理模块;命令行终端;系统进程管理,实时进程查看,用户桌面视图墙轮播等功能,被控服务端支持绿色启动及以系统服务方式安装,解决了WindowsSession桌面切换限制,实现了捕获UAC,WinLogon桌面;系统实现了中间会话服务器,可支持不同平台多主控端同时监控同一被控端,项目完全采用C#.NET开发,代码仅供参考,项目不定时更新,欢迎关注点星星,fork。欢迎入群技术交流:905958449 :laughing: :blush: # 申明 - 作为创作者,我对由此软件引起的任何行为和/或损害不承担任何责任。 您对自己的行为承担全部责任,并承认此软件仅用于教育和研究目的。 不得用于您不拥有或有权使用的任何系统。 使用此软件,您自动同意上述内容,感谢支持。 # 背景 - - 项目仅是个人在平时开发中的技术试验性项目,用于积累在工作中所遇到的有趣技术,或者试验新技术,比如系统架构,语法等。经过几次重构,系统相对比较成熟了,决定开源反馈开源社区,希望更多人能和我一起进步,欢迎吐槽改进。 + - 项目仅是个人技术总结项目,总结在工作中所遇到的有趣技术,测试新技术,比如系统架构,语法等。经过几次重构,系统相对比较成熟了,决定开源反馈开源社区,希望更多人能和我一起进步,欢迎吐槽改进。 ![主控界面](https://images.gitee.com/uploads/images/2019/0717/225727_cc5c40c8_1654743.jpeg "主控制界面") ![创建服务端](https://images.gitee.com/uploads/images/2019/0717/225801_d0ccad61_1654743.jpeg "创建服务端") @@ -17,21 +16,20 @@ # 系统项目结构 -### SiMay.Common.Core【公共核心功能】## - - SiMay.Basic--框架级通用库 - - SiMay.Core--系统统一公共库【如统一的通讯指令丶共用组件丶通信数据实体丶字符串编解码等..】 - - SiMay.Serialize--轻量级二进制序列化库【作用:系统通信数据实体化】 +### SiMay.Core【公共核心功能】## + - SiMay.Basic--基础通用库 + - SiMay.Core--系统核心统一公共库【统一通讯指令丶共用组件丶通信数据实体等..】 + - SiMay.Serialize--轻量级高性能二进制序列化库【作用:系统通信数据实体化】 ### SiMay.RemoteMonitor【主控端】## - SiMay.RemoteControlsCore 主控端核心库 - SiMay.RemoteMonitor--Windows主控端(基于核心库) - - SiMay.HttpRemoteMonitor【计划,未完成】 --Http主控端展示层(基于核心库,支持.NET Core),基于WebSocket与前端通信 - - WebRemoteMonitorSystem--Web监控前端 + - SiMay.RemoteMonitorForWeb【计划,未完成】 --Web主控端后端(基于核心库,支持.NET Core),基于WebSocket与前端通信 + - SiMay.RemoteMonitorForWebSite【计划,未完成】 --Web监控前端 ### SiMay.RemoteService【远程服务端】## - - SiMay.RemoteService --内存加载Loader - - SiMay.RemoteClient.NewCore--被控端核心库/被控端主程序 - - SiMay.Daemon--服务端守护进程【未启用】 + - SiMay.RemoteService.Loader --内存加载Loader,实现远程内存载入被控端核心库 + - SiMay.ServiceCore --被控端核心库/被控端主程序 ### SiMay.SessionProvider【会话提供库】## - SiMay.Net.SessionProvider--会话提供库【作用:提供服务器监听模式或者中间会话代理协议】 @@ -39,46 +37,48 @@ - SiMay.Net.SessionProviderService--中间会话代理服务器【作用:提供保持服务端会话保持丶数据转发功能,基于此实现多平台端监控】 ### SiMay.Sockets【Socket通信库】## - - SiMay.Socket.V4 1.0--轻量级通信引擎【计划.NET Core】 + - SiMay.Socket.Standard --轻量级通信引擎 - SiMaySocketTestApp--通信引擎测试程序 -### SiMay.Web.MonitorService【Web监控服务端】## - - SiMay.Net.HttpRemoteMonitorService--WebSocket监控服务端【计划弃用】 +### SiMay.Web.MonitorService【Web监控服务端,已弃用】## + - SiMay.Net.HttpRemoteMonitorService--WebSocket监控服务端 ### 编译 -1.Bin目录为生成目录,重新生成后,主控程序将编译到此目录,Bin->dat目录为服务端目录,被控服务端编译后在此。(没有目录新建一下) +1.Bin为编译目录,重新生成后,主控程序将编译到此目录,Bin->dat目录为被控服务端目录,被控服务端编译后在此。(没有目录新建一下) ### 运行 1.局域网 -主控端:打开主控程序SiMayRemoteMonitor.exe,确认系统设置服务器地址为0.0.0.0(监听本机所有网卡),端口默认5200,确认会话模式为:本地服务器,然后保存配置重启程序, +主控端:打开位与Bin目录下的主控端程序SiMayRemoteMonitor.exe,确认系统设置服务器地址为0.0.0.0(监听本机所有网卡),端口默认5200,使用会话模式为=本地服务器,然后保存配置重启程序, 重启后日志输出监听成功,即主控端设置正确。 -被控服务端:打开主控端-->创建客户-->地址输入本机ip地址(或127.0.0.1)-->端口设置为服务端监听端口(默认5200)-->点击连接测试检查配置是否正确-->创建服务端文件,服务端文件即为配置完成的被控端程序(如提示找不到文件,请检查编译步骤是否正确),双击运行即可连接至主控端,如连接不成功,请检查上述步骤是否配置正确。 +被控服务端创建:打开主控端-->创建客户-->地址输入本机物理地址(或127.0.0.1),端口设置为服务端监听端口(默认5200)-->点击连接测试检查配置是否正确-->创建服务端文件,服务端文件即为配置完成的被控端程序(如提示找不到文件,请检查被控服务程序是否存在[编译步骤是否正确]),双击运行被控服务程序即可在主控端看见服务在线信息,如主控端无在线信息,请检查上述步骤是否配置正确。 2.广域网 -条件:需要主控端处于公网环境(或者设置路由内网映射),并且开放主控端监听端口。 +条件:需要主控端处于公网环境(或者设置路由内网映射、使用内网映射工具[如花生壳,内网通]),并且开放主控端监听端口(注意检查端口是否开放、防火墙通行规则)。 创建客户端-->被控服务端连接至主控端的公网地址,端口即可 3.中间服务器部署 -条件:需要中间服务器处于公网环境(或者设置路由内网映射),并且开放中间服务器监听端口(默认522端口)。 +条件:需要中间服务器处于公网环境(建议部署在公网服务器,或者设置路由内网映射),并且开放中间服务器监听端口(默认522端口、注意检查端口是否开放、防火墙通行规则)。 -设置 主控端设置 会话服务器地址 为 中间服务器的地址,端口。-->设置会话模式为:中间会话模式-->(中间会话服务器系统设置位于系统菜单右键)确认连接密码与中间服务器密码一致。-->创建客户端,将ip,端口指向中间服务器即可 +主控端设置: 系统设置-->会话服务器地址 输入 中间服务器的公网地址,端口。-->设置会话模式为:中间会话模式-->确认AccessKey与中间服务器Accesskey一致。(中间会话服务器系统设置位于标题栏系统菜单右键)-->创建客户端并选择会话模式为中间会话模式,ip,端输入中间服务器的公网地址即可 4.web端监控【完善中,不可用】 配置IIS,部署SiMay.WebRemoteMonitor网站,编译启动SiMay.Net.HttpRemoteMonitorService,配置地址指向中间服务器ip,端口即可(无系统设置,需手动配置配置文件),如连接成功,中间服务器出现主控制连接在线日志即可 -使用浏览器,访问SiMay.WebRemoteMonitor网站,输入SiMay.Net.HttpRemoteMonitorService配置的账号密码即可,当有中间服务器有被控端会话时,将自动连接至http服务,此时网页可看到被控服务端计算机屏幕视图,长按视图打开更多功能。 +使用浏览器,访问SiMay.WebRemoteMonitor网站,输入SiMay.Net.HttpRemoteMonitorService配置的账号密码即可,当有中间服务器有被控端会话时,将自动连接至http服务,连接成功后网页可看到被控服务端计算机桌面视图,长按视图可打开更多功能。 ### 技术架构 - 基于IOCP的异步Socket高性能通信模型 - - 采用热区域逐行扫描算法的远程桌面 - - 语音通讯采用Windows WaInXX等Api实现 - - 视频监控采用Dx组件捕获图像 - - 键盘记录采用HOOK技术捕获全局键盘消息 - - Web端监控采用了WebSocket等技术实现 + - 基于实体的实体消息协议 + - 热区域逐行扫描算法的远程桌面 + - 基于组件式的系统架构 + - 基于Windows WaInXX系列实现的语音通讯 + - 基于Dx组件捕获摄像头 + - 基于HOOK技术的键盘记录 + - 基于WebSocket技术实现Web端监控 ### 开发环境 - - Visual Studio 2015 以上 + - 建议 Visual Studio 2019 企业版 ### 参与贡献 - Fork 本仓库 @@ -87,33 +87,34 @@ - 新建 Pull Request ### 未来构想 - - 实现多平台控制端同步监控 - 完善更多web监控功能 ### SiMay远程监控管理系统更新说明 ### 6.0更新 -1. 跨.NET Core支持,完善中间会话服务器、Web端实时监控管理 --未完成 -2. 二进制序列化器采用反射缓存,提高系统性能 -- 2020.1.25 -3.屏幕视图轮播 --2020.1.15 +1. 跨.NET Core支持,重构中间会话服务器 --2020.2.15 +2. 二进制序列化器采用反射缓存,提高系统性能 -- 2020.1.25 +3. 屏幕视图轮播 --2020.1.15 +4. Web端主控端 --未实现 +5. SOCK5代理,并兼容中间服务转发 -- 未实现 ### 5.0更新 -1. 优化了通讯库,支持FULL丶PACK数据处理方式,更友好的配置接口 +1. 优化了通讯库,支持FULL丶PACK数据处理方式,实现了更友好的配置接口 2. 新增中间会话转发服务,增加了SessionProvider层,控制端支持监听模式丶中间会话模式,在此基础上实现了Web监控服务,支持Web方式监控 -3. 增强了远程桌面,支持全屏监控的远程鼠标控制 -4. 重构代码结构,实现了组件化代码框架,即使不熟悉框架也能轻松扩展功能 --2019.5.19 -5. 远程桌面采用了热区域扫描算法,仅扫描可视区域变化部分,优化了远程桌面模块,速度更加快了 --2019.4.2 -6. 增强系统管理模块,实时进程监控 8.28 +3. 增强了远程桌面模块,支持全屏监控的远程鼠标控制及多屏幕切换 +4. 重构代码结构,实现了组件化系统框架,屏蔽了系统底层实现细节,增强了可扩展性 --2019.5.19 +5. 远程桌面增加了可视区域扫描算法,仅扫描可视区域变化部分,优化了远程桌面模块,速度更加快了 --2019.4.2 +6. 增强系统管理模块,实现了进程实时监控 --8.28 7. 语音监听,视频监控支持录制功能 --待实现 -8. 被控服务实现了服务方式安装,实现了Session隔离穿透捕获桌面(锁屏,UAC), --11.9 -9. 文件管理功能增强,重构文件夹传输 2019.7.13 -10. 系统传输数据实体化 -- 2019-6-4 +8. 被控服务实现了以服务方式安装,使用服务方式可实现Session隔离穿透捕获桌面(锁屏,UAC), --11.9 +9. 文件管理功文件夹传输重构优化 2019.7.13 +10. 系统传输数据消息实体化 -- 2019-6-4 11. 二进制序列化器采用反射缓存,提高系统性能 --已实现 -12. 远程桌面增加质量调整,低速率网络下控制更加流畅 -- 7.27 +12. 远程桌面增加画面质量调整,优化低速率网络下的控制体验,使画面更加流畅 -- 7.27 13. 支持远程更新服务端 -- 7.27 14. 增加列表排序功能 -- 7.27 -15. 注册表组件更新,支持二进制丶多种类型数据编辑 9.6 -16. 重构主控端,实现主控端逻辑与展示层(winform)彻底分离,实现核心逻辑复用为跨平台监控打好基础 - 11.2 +15. 注册表组件更新,支持二进制丶多种类型数据编辑 -- 9.6 +16. 重构主控端,主控端逻辑核心库与展示层彻底分离(如:基于核心库横向扩展Web主控端,实现多平台逻辑复用) - 11.2 ### 4.0更新 1. 重写了通讯层,解决网络环境极差时频繁断开连接的情况,实现了对象池,以更好的并发能力应对大规模的客户端数据交互 diff --git a/SiMay.Basic/GZipHelper.cs b/SiMay.Basic/GZipHelper.cs index 6d1548a..04afb29 100644 --- a/SiMay.Basic/GZipHelper.cs +++ b/SiMay.Basic/GZipHelper.cs @@ -27,13 +27,14 @@ namespace SiMay.Basic catch { } return buffer; } - public static byte[] Decompress(byte[] data) + => Decompress(data, 0, data.Length); + public static byte[] Decompress(byte[] data, int offset, int length) { byte[] buffer = null; try { - MemoryStream ms = new MemoryStream(data); + MemoryStream ms = new MemoryStream(data, offset, length); GZipStream zip = new GZipStream(ms, CompressionMode.Decompress, true); MemoryStream msreader = new MemoryStream(); buffer = new byte[0x1000]; diff --git a/SiMay.Basic/Properties/AssemblyInfo.cs b/SiMay.Basic/Properties/AssemblyInfo.cs deleted file mode 100644 index b8e5859..0000000 --- a/SiMay.Basic/Properties/AssemblyInfo.cs +++ /dev/null @@ -1,36 +0,0 @@ -using System.Reflection; -using System.Runtime.CompilerServices; -using System.Runtime.InteropServices; - -// 有关程序集的一般信息由以下 -// 控制。更改这些特性值可修改 -// 与程序集关联的信息。 -[assembly: AssemblyTitle("SiMay.Basic")] -[assembly: AssemblyDescription("")] -[assembly: AssemblyConfiguration("")] -[assembly: AssemblyCompany("")] -[assembly: AssemblyProduct("SiMay.Basic")] -[assembly: AssemblyCopyright("Copyright © 2019")] -[assembly: AssemblyTrademark("")] -[assembly: AssemblyCulture("")] - -// 将 ComVisible 设置为 false 会使此程序集中的类型 -//对 COM 组件不可见。如果需要从 COM 访问此程序集中的类型 -//请将此类型的 ComVisible 特性设置为 true。 -[assembly: ComVisible(false)] - -// 如果此项目向 COM 公开,则下列 GUID 用于类型库的 ID -[assembly: Guid("b30cd716-698a-4da2-bd1a-c152b16993c0")] - -// 程序集的版本信息由下列四个值组成: -// -// 主版本 -// 次版本 -// 生成号 -// 修订号 -// -// 可以指定所有值,也可以使用以下所示的 "*" 预置版本号和修订号 -//通过使用 "*",如下所示: -// [assembly: AssemblyVersion("1.0.*")] -[assembly: AssemblyVersion("1.0.0.0")] -[assembly: AssemblyFileVersion("1.0.0.0")] diff --git a/SiMay.Basic/RectangleHelper.cs b/SiMay.Basic/RectangleHelper.cs index 4c78898..2f9f81a 100644 --- a/SiMay.Basic/RectangleHelper.cs +++ b/SiMay.Basic/RectangleHelper.cs @@ -8,7 +8,7 @@ namespace SiMay.Basic { public class RectangleHelper { - public static bool WhetherContainsInDisplayRectangle(Rectangle containerRect, Rectangle childRect) + public static bool WhetherContainsInRectangle(Rectangle containerRect, Rectangle childRect) { var result = childRect.Y + childRect.Height >= containerRect.Y && childRect.Y <= containerRect.Bottom; return result; diff --git a/SiMay.Basic/SiMay.Basic.csproj b/SiMay.Basic/SiMay.Basic.csproj index 9b5e5dd..c7ed923 100644 --- a/SiMay.Basic/SiMay.Basic.csproj +++ b/SiMay.Basic/SiMay.Basic.csproj @@ -1,68 +1,15 @@ - - - + + - Debug - AnyCPU - {B30CD716-698A-4DA2-BD1A-C152B16993C0} - Library - Properties - SiMay.Basic - SiMay.Basic - v4.6.1 - 512 - true - + netstandard2.0 - - true - full - false - bin\Debug\ - DEBUG;TRACE - prompt - 4 - 8.0 - false + + + ..\Bin\ - - pdbonly - true - bin\Release\ - TRACE - prompt - 4 - 8.0 - false + + + ..\Bin\ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - \ No newline at end of file + + diff --git a/SiMay.Core/Enums/ConnectionWorkType.cs b/SiMay.Core/Enums/ConnectionWorkType.cs index c0d84ca..9bee62d 100644 --- a/SiMay.Core/Enums/ConnectionWorkType.cs +++ b/SiMay.Core/Enums/ConnectionWorkType.cs @@ -7,8 +7,19 @@ namespace SiMay.Core.Enums { public enum ConnectionWorkType : Byte { - MAINCON,//主连接 - WORKCON,//工作连接 - NONE,//未确认的连接 + /// + /// 主服务连接 + /// + MAINCON, + + /// + /// 应用服务工作连接 + /// + WORKCON, + + /// + /// 未识别的连接 + /// + NONE, } } diff --git a/SiMay.Core/Enums/DifferStatus.cs b/SiMay.Core/Enums/DifferStatus.cs index 623d9c5..43cb1a2 100644 --- a/SiMay.Core/Enums/DifferStatus.cs +++ b/SiMay.Core/Enums/DifferStatus.cs @@ -7,8 +7,19 @@ namespace SiMay.Core.Enums { public enum DifferStatus { - FULLDIFFERENCES, - NEXTSCREEN, - COMPLETE + /// + /// 全屏扫描完成 + /// + FULL_DIFFERENCES, + + /// + /// 差异下一帧扫描完成 + /// + NEXT_SCREEN, + + /// + /// 完成扫描 + /// + COMPLETED } } diff --git a/SiMay.Core/Enums/FileType.cs b/SiMay.Core/Enums/FileType.cs index 384da5d..25d3d7d 100644 --- a/SiMay.Core/Enums/FileType.cs +++ b/SiMay.Core/Enums/FileType.cs @@ -7,8 +7,19 @@ namespace SiMay.Core.Enums { public enum FileType : Byte { + /// + /// 磁盘 + /// Disk, + + /// + /// 文件 + /// File, + + /// + /// 文件夹 + /// Directory } } diff --git a/SiMay.Core/Enums/MessageIcon.cs b/SiMay.Core/Enums/MessageIcon.cs index 799f411..743f446 100644 --- a/SiMay.Core/Enums/MessageIcon.cs +++ b/SiMay.Core/Enums/MessageIcon.cs @@ -7,9 +7,24 @@ namespace SiMay.Core.Enums { public enum MessageIcon : Byte { + /// + /// 错误信息 + /// Error, + + /// + /// 问号 + /// Question, + + /// + /// 信息 + /// InforMation, + + /// + /// 叹号 + /// Exclaim } } diff --git a/SiMay.Core/Enums/MouseKeyEnum.cs b/SiMay.Core/Enums/MouseKeyEnum.cs index 98ac04a..2f907e6 100644 --- a/SiMay.Core/Enums/MouseKeyEnum.cs +++ b/SiMay.Core/Enums/MouseKeyEnum.cs @@ -7,15 +7,47 @@ namespace SiMay.Core.Enums { public enum MOUSEKEY_ENUM : byte { + /// + /// 鼠标移动 + /// Move, + + /// + /// 左键按下 + /// LeftDown, + + /// + /// 左键抬起 + /// LeftUp, + MiddleDown, MiddleUp, + + /// + /// 右键按下 + /// RightDown, + + /// + /// 右键抬起 + /// RightUp, + + /// + /// 滚轮 + /// Wheel, + + /// + /// 按键按下 + /// KeyDown, + + /// + /// 按键抬起 + /// KeyUp } } diff --git a/SiMay.Core/Enums/RemoteUpdateType.cs b/SiMay.Core/Enums/RemoteUpdateType.cs index 23f67ae..a49c2dc 100644 --- a/SiMay.Core/Enums/RemoteUpdateType.cs +++ b/SiMay.Core/Enums/RemoteUpdateType.cs @@ -7,7 +7,14 @@ namespace SiMay.Core.Enums { public enum RemoteUpdateType { + /// + /// URL下载更新 + /// Url, + + /// + /// 文件上传更新 + /// File } } diff --git a/SiMay.Core/Enums/SystemSessionType.cs b/SiMay.Core/Enums/SystemSessionType.cs index 1fe0f8f..82ba4d8 100644 --- a/SiMay.Core/Enums/SystemSessionType.cs +++ b/SiMay.Core/Enums/SystemSessionType.cs @@ -7,14 +7,49 @@ namespace SiMay.Core.Enums { public enum SystemSessionType : byte { + /// + /// 关机 + /// Shutdown = 0, + + /// + /// 重启 + /// Reboot = 1, + + /// + /// 注册表启动 + /// RegStart = 2, + + /// + /// 取消注册表启动 + /// RegCancelStart = 3, + + /// + /// 隐藏自身文件及日志 + /// AttributeHide = 4, + + /// + /// 显示自身文件 + /// AttributeShow = 5, + + /// + /// 退出程序 + /// Unstall = 6, + + /// + /// 以服务安装 + /// InstallService = 7, + + /// + /// 卸载服务 + /// UnInstallService = 8 } } diff --git a/SiMay.Core/MessageHelper.cs b/SiMay.Core/MessageHelper.cs index 43600ee..cdc3e91 100644 --- a/SiMay.Core/MessageHelper.cs +++ b/SiMay.Core/MessageHelper.cs @@ -1,6 +1,6 @@ using System; using SiMay.Core.Extensions; -using static SiMay.Serialize.PacketSerializeHelper; +using static SiMay.Serialize.Standard.PacketSerializeHelper; namespace SiMay.Core { diff --git a/SiMay.Core/ScreenSpy/ScreenSpy.cs b/SiMay.Core/ScreenSpy/ScreenSpy.cs index 136b045..5435729 100644 --- a/SiMay.Core/ScreenSpy/ScreenSpy.cs +++ b/SiMay.Core/ScreenSpy/ScreenSpy.cs @@ -152,7 +152,7 @@ namespace SiMay.Core.ScreenSpy FragmentData = _jpgCompression.Compress(m_new) } }; - this.OnDifferencesNotice?.Invoke(fragments, DifferStatus.NEXTSCREEN); + this.OnDifferencesNotice?.Invoke(fragments, DifferStatus.NEXT_SCREEN); } else m_old.Dispose(); @@ -166,7 +166,7 @@ namespace SiMay.Core.ScreenSpy _clientHotRegion = rect; - this.OnDifferencesNotice?.Invoke(null, DifferStatus.COMPLETE); + this.OnDifferencesNotice?.Invoke(null, DifferStatus.COMPLETED); } public void FullFindDifferences(bool hotRegionScan, Rectangle rect) @@ -256,7 +256,7 @@ namespace SiMay.Core.ScreenSpy if (this.OnDifferencesNotice != null) { - this.OnDifferencesNotice(fragments.ToArray(), DifferStatus.FULLDIFFERENCES); + this.OnDifferencesNotice(fragments.ToArray(), DifferStatus.FULL_DIFFERENCES); fragments.Clear(); } } diff --git a/SiMay.Core/SiMay.Core.csproj b/SiMay.Core/SiMay.Core.csproj index 819fe7c..4ad0742 100644 --- a/SiMay.Core/SiMay.Core.csproj +++ b/SiMay.Core/SiMay.Core.csproj @@ -163,12 +163,12 @@ - {B30CD716-698A-4DA2-BD1A-C152B16993C0} + {8f2f35cb-d5ee-4d92-b42f-bcffbf9c9d4f} SiMay.Basic - - {4888d6bb-46d9-4519-8758-e13e397aa226} - SiMay.Serialize + + {9525a4aa-6731-4ab2-8cd0-addf7940fe32} + SiMay.Serialize.Standard diff --git a/SiMay.Net.SessionProvider.Core/Entitys/AckPacket.cs b/SiMay.Net.SessionProvider.Core/Entitys/AckPacket.cs new file mode 100644 index 0000000..c4f1cca --- /dev/null +++ b/SiMay.Net.SessionProvider.Core/Entitys/AckPacket.cs @@ -0,0 +1,15 @@ +using SiMay.ReflectCache; +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; + +namespace SiMay.Net.SessionProvider.Core +{ + public class AckPacket : EntitySerializerBase + { + public ConnectionWorkType Type { get; set; } + public long AccessId { get; set; } + public long AccessKey { get; set; } + } +} diff --git a/SiMay.Net.SessionProvider.Core/Entitys/LogOutPacket.cs b/SiMay.Net.SessionProvider.Core/Entitys/LogOutPacket.cs new file mode 100644 index 0000000..bed94c5 --- /dev/null +++ b/SiMay.Net.SessionProvider.Core/Entitys/LogOutPacket.cs @@ -0,0 +1,15 @@ +using SiMay.ReflectCache; +using System; +using System.Collections.Generic; +using System.Text; + +namespace SiMay.Net.SessionProvider.Core +{ + public class LogOutPacket : EntitySerializerBase + { + /// + /// 登出原因 + /// + public string Message { get; set; } + } +} diff --git a/SiMay.Net.SessionProvider.Core/Entitys/MessageDataPacket.cs b/SiMay.Net.SessionProvider.Core/Entitys/MessageDataPacket.cs new file mode 100644 index 0000000..0b9c236 --- /dev/null +++ b/SiMay.Net.SessionProvider.Core/Entitys/MessageDataPacket.cs @@ -0,0 +1,16 @@ +using SiMay.ReflectCache; +using System; +using System.Collections.Generic; +using System.Text; + +namespace SiMay.Net.SessionProvider.Core +{ + public class MessageDataPacket : EntitySerializerBase + { + public long AccessId { get; set; } + + public long DispatcherId { get; set; } + + public byte[] Data { get; set; } + } +} diff --git a/SiMay.Net.SessionProvider.Core/Entitys/SessionClosedPacket.cs b/SiMay.Net.SessionProvider.Core/Entitys/SessionClosedPacket.cs new file mode 100644 index 0000000..92cb921 --- /dev/null +++ b/SiMay.Net.SessionProvider.Core/Entitys/SessionClosedPacket.cs @@ -0,0 +1,12 @@ +using SiMay.ReflectCache; +using System; +using System.Collections.Generic; +using System.Text; + +namespace SiMay.Net.SessionProvider.Core +{ + public class SessionClosedPacket : EntitySerializerBase + { + public long Id { get; set; } + } +} diff --git a/SiMay.Net.SessionProvider.Core/Entitys/SessionPacket.cs b/SiMay.Net.SessionProvider.Core/Entitys/SessionPacket.cs new file mode 100644 index 0000000..581a970 --- /dev/null +++ b/SiMay.Net.SessionProvider.Core/Entitys/SessionPacket.cs @@ -0,0 +1,19 @@ +using SiMay.ReflectCache; +using System; +using System.Collections.Generic; +using System.Text; + +namespace SiMay.Net.SessionProvider.Core +{ + public class SessionPacket : EntitySerializerBase + { + public SessionItemPacket[] SessionItems { get; set; } + } + + public class SessionItemPacket : EntitySerializerBase + { + public long Id { get; set; } + + public byte[] ACKPacketData { get; set; } + } +} diff --git a/SiMay.Net.SessionProvider.Core/Enums/ConnectionWorkType.cs b/SiMay.Net.SessionProvider.Core/Enums/ConnectionWorkType.cs new file mode 100644 index 0000000..d452dee --- /dev/null +++ b/SiMay.Net.SessionProvider.Core/Enums/ConnectionWorkType.cs @@ -0,0 +1,35 @@ +using System; +using System.Collections.Generic; +using System.ComponentModel; +using System.Text; + +namespace SiMay.Net.SessionProvider.Core +{ + public enum ConnectionWorkType + { + /// + /// 主被控服务连接 + /// + MainServiceConnection, + + /// + /// 服务工作连接 + /// + ApplicationServiceConnection, + + /// + /// 主控端连接 + /// + MainApplicationConnection, + + /// + /// 应用工作连接 + /// + ApplicationConnection, + + /// + /// 未识别 + /// + None + } +} diff --git a/SiMay.Net.SessionProvider.Core/Enums/MessageHead.cs b/SiMay.Net.SessionProvider.Core/Enums/MessageHead.cs new file mode 100644 index 0000000..9d28f30 --- /dev/null +++ b/SiMay.Net.SessionProvider.Core/Enums/MessageHead.cs @@ -0,0 +1,55 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace SiMay.Net.SessionProvider.Core +{ + /// + /// APP_XX : 主控端消息 + /// MID_XX : 中间服务消息 + /// + public enum MessageHead + { + /// + /// //获取所有Session + /// + APP_PULL_SESSION, + + /// + /// 关联Session信息 + /// + MID_SESSION, + + /// + /// Session离线 + /// + MID_SESSION_CLOSED, + + /// + /// 发起一个工作连接 + /// + MID_APPWORK, + + /// + /// 向主服务连接发送消息 + /// + APP_MESSAGE_DATA, + + /// + /// 转发的主服务连接数据 + /// + MID_MESSAGE_DATA, + + /// + /// AccessKey错误 + /// + MID_ACCESS_KEY_WRONG, + + /// + /// 登出 + /// + MID_LOGOUT, + } +} diff --git a/SiMay.Net.SessionProvider.Core/Extension/UnicodeExtensions.cs b/SiMay.Net.SessionProvider.Core/Extension/UnicodeExtensions.cs new file mode 100644 index 0000000..3c5babd --- /dev/null +++ b/SiMay.Net.SessionProvider.Core/Extension/UnicodeExtensions.cs @@ -0,0 +1,19 @@ +using System.Text; + +namespace SiMay.Net.SessionProvider.Core +{ + + public static class UnicodeExtensions + { + + public static string ToUnicodeString(this byte[] data) + { + return Encoding.Unicode.GetString(data); + } + + public static byte[] UnicodeStringToBytes(this string str) + { + return Encoding.Unicode.GetBytes(str); + } + } +} \ No newline at end of file diff --git a/SiMay.Net.SessionProvider.Core/Helper/MessageHelper.cs b/SiMay.Net.SessionProvider.Core/Helper/MessageHelper.cs new file mode 100644 index 0000000..7162457 --- /dev/null +++ b/SiMay.Net.SessionProvider.Core/Helper/MessageHelper.cs @@ -0,0 +1,105 @@ +using System; +using static SiMay.Serialize.Standard.PacketSerializeHelper; + +namespace SiMay.Net.SessionProvider.Core +{ + /// + /// 消息处理帮助(格式:Int16的消息头 + payload) + /// + public static class MessageHelper + { + /// + /// 序列化数据实体,并封装消息头 + /// + /// + /// + /// + public static byte[] CopyMessageHeadTo(T cmd, object entity) + where T : struct + { + return CopyMessageHeadTo(cmd, SerializePacket(entity)); + } + + /// + /// + /// + /// + /// + /// + /// + public static byte[] CopyMessageHeadTo(T cmd, byte[] data, int size) + where T : struct + { + byte[] buff = new byte[size + sizeof(short)]; + BitConverter.GetBytes(Convert.ToInt16(cmd)).CopyTo(buff, 0); + Array.Copy(data, 0, buff, sizeof(Int16), size); + + return buff; + } + + /// + /// 构建消息至数据头部 + /// + /// + /// + /// + public static byte[] CopyMessageHeadTo(T cmd, byte[] data = null) + where T : struct + { + if (data == null) + data = new byte[] { }; + + return CopyMessageHeadTo(cmd, data, data.Length); + } + + /// + /// 构建消息头至数据头部 + /// + /// 消息头 + /// 字符串 + /// + public static byte[] CopyMessageHeadTo(T cmd, string str) + where T : struct + { + byte[] data = str.UnicodeStringToBytes(); + + return CopyMessageHeadTo(cmd, data, data.Length); + } + + /// + /// 获取消息头 + /// + /// + /// + public static T GetMessageHead(this byte[] data) + where T : struct + { + return (T)Enum.ToObject(typeof(T), BitConverter.ToInt16(data, 0)); + } + + /// + /// 获取消息载体 + /// + /// + /// + public static byte[] GetMessagePayload(this byte[] data) + { + byte[] payload = new byte[data.Length - sizeof(short)]; + Array.Copy(data, sizeof(short), payload, 0, payload.Length); + return payload; + } + + /// + /// 反序列化数据实体 + /// + /// + /// + /// + public static T GetMessageEntity(this byte[] data) + where T : new() + { + var entity = DeserializePacket(GetMessagePayload(data)); + return entity; + } + } +} \ No newline at end of file diff --git a/SiMay.Net.SessionProvider.Core/SiMay.Net.SessionProvider.Core.csproj b/SiMay.Net.SessionProvider.Core/SiMay.Net.SessionProvider.Core.csproj index 606ec5e..01dfafc 100644 --- a/SiMay.Net.SessionProvider.Core/SiMay.Net.SessionProvider.Core.csproj +++ b/SiMay.Net.SessionProvider.Core/SiMay.Net.SessionProvider.Core.csproj @@ -1,60 +1,15 @@ - - - + + - Debug - AnyCPU - {8BFDB408-D26D-4689-B426-BE45AD195880} - Library - Properties - SiMay.Net.SessionProvider.Core - SiMay.Net.SessionProvider.Core - v4.6.1 - 512 - + netstandard2.0 - - true - full - false - bin\Debug\ - DEBUG;TRACE - prompt - 4 - 8.0 - false - - - pdbonly - true - bin\Release\ - TRACE - prompt - 4 - 8.0 - false - - - - - - - - - - - + - - - - + + - - {4888D6BB-46D9-4519-8758-E13E397AA226} - SiMay.Serialize - + - - \ No newline at end of file + + diff --git a/SiMay.Net.SessionProvider.Core_/Helper/MessageHelper.cs b/SiMay.Net.SessionProvider.Core_/Helper/MessageHelper.cs new file mode 100644 index 0000000..836c8d3 --- /dev/null +++ b/SiMay.Net.SessionProvider.Core_/Helper/MessageHelper.cs @@ -0,0 +1,105 @@ +using System; +using static SiMay.Serialize.Standard.PacketSerializeHelper; + +namespace SiMay.Net.SessionProviderServiceCore +{ + /// + /// 消息处理帮助(格式:Int16的消息头 + payload) + /// + public static class MessageHelper + { + /// + /// 序列化数据实体,并封装消息头 + /// + /// + /// + /// + public static byte[] CopyMessageHeadTo(T cmd, object entity) + where T : struct + { + return CopyMessageHeadTo(cmd, SerializePacket(entity)); + } + + /// + /// + /// + /// + /// + /// + /// + public static byte[] CopyMessageHeadTo(T cmd, byte[] data, int size) + where T : struct + { + byte[] buff = new byte[size + sizeof(short)]; + BitConverter.GetBytes(Convert.ToInt16(cmd)).CopyTo(buff, 0); + Array.Copy(data, 0, buff, sizeof(Int16), size); + + return buff; + } + + /// + /// 构建消息至数据头部 + /// + /// + /// + /// + public static byte[] CopyMessageHeadTo(T cmd, byte[] data = null) + where T : struct + { + if (data == null) + data = new byte[] { }; + + return CopyMessageHeadTo(cmd, data, data.Length); + } + + /// + /// 构建消息头至数据头部 + /// + /// 消息头 + /// 字符串 + /// + public static byte[] CopyMessageHeadTo(T cmd, string str) + where T : struct + { + byte[] data = str.UnicodeStringToBytes(); + + return CopyMessageHeadTo(cmd, data, data.Length); + } + + /// + /// 获取消息头 + /// + /// + /// + public static T GetMessageHead(this byte[] data) + where T : struct + { + return (T)Enum.ToObject(typeof(T), BitConverter.ToInt16(data, 0)); + } + + /// + /// 获取消息载体 + /// + /// + /// + public static byte[] GetMessagePayload(this byte[] data) + { + byte[] payload = new byte[data.Length - sizeof(short)]; + Array.Copy(data, sizeof(short), payload, 0, payload.Length); + return payload; + } + + /// + /// 反序列化数据实体 + /// + /// + /// + /// + public static T GetMessageEntity(this byte[] data) + where T : new() + { + var entity = DeserializePacket(GetMessagePayload(data)); + return entity; + } + } +} \ No newline at end of file diff --git a/SiMay.Net.SessionProvider.Core/LogHelper.cs b/SiMay.Net.SessionProvider.Core_/LogHelper.cs similarity index 100% rename from SiMay.Net.SessionProvider.Core/LogHelper.cs rename to SiMay.Net.SessionProvider.Core_/LogHelper.cs diff --git a/SiMay.Net.SessionProvider.Core/MsgCommand.cs b/SiMay.Net.SessionProvider.Core_/MsgCommand.cs similarity index 100% rename from SiMay.Net.SessionProvider.Core/MsgCommand.cs rename to SiMay.Net.SessionProvider.Core_/MsgCommand.cs diff --git a/SiMay.Net.SessionProvider.Core/Properties/AssemblyInfo.cs b/SiMay.Net.SessionProvider.Core_/Properties/AssemblyInfo.cs similarity index 100% rename from SiMay.Net.SessionProvider.Core/Properties/AssemblyInfo.cs rename to SiMay.Net.SessionProvider.Core_/Properties/AssemblyInfo.cs diff --git a/SiMay.Serialize/SiMay.Serialize.csproj b/SiMay.Net.SessionProvider.Core_/SiMay.Net.SessionProvider.Core.csproj similarity index 78% rename from SiMay.Serialize/SiMay.Serialize.csproj rename to SiMay.Net.SessionProvider.Core_/SiMay.Net.SessionProvider.Core.csproj index 001ecb4..96ee0a0 100644 --- a/SiMay.Serialize/SiMay.Serialize.csproj +++ b/SiMay.Net.SessionProvider.Core_/SiMay.Net.SessionProvider.Core.csproj @@ -4,14 +4,13 @@ Debug AnyCPU - {4888D6BB-46D9-4519-8758-E13E397AA226} + {8BFDB408-D26D-4689-B426-BE45AD195880} Library Properties - SiMay.Serialize - SiMay.Serialize + SiMay.Net.SessionProvider.Core + SiMay.Net.SessionProvider.Core v4.6.1 512 - true @@ -38,6 +37,7 @@ + @@ -45,14 +45,11 @@ - - - - + + + - - + - \ No newline at end of file diff --git a/SiMay.Net.SessionProvider.Core/Win32Api.cs b/SiMay.Net.SessionProvider.Core_/Win32Api.cs similarity index 100% rename from SiMay.Net.SessionProvider.Core/Win32Api.cs rename to SiMay.Net.SessionProvider.Core_/Win32Api.cs diff --git a/SiMay.Net.SessionProvider/MessageHelper.cs b/SiMay.Net.SessionProvider/MessageHelper.cs index 54e7f08..aadce35 100644 --- a/SiMay.Net.SessionProvider/MessageHelper.cs +++ b/SiMay.Net.SessionProvider/MessageHelper.cs @@ -17,7 +17,7 @@ namespace SiMay.Net.SessionProvider dataBuilder.AddRange(body); return dataBuilder.ToArray(); } - public static void SendMessage(TcpSocketSaeaSession session, MsgCommand cmd, byte[] body = null) + public static void SendMessage(TcpSocketSaeaSession session, MessageHead cmd, byte[] body = null) { if (body == null) body = new byte[] { 0 }; diff --git a/SiMay.Net.SessionProvider/Properties/AssemblyInfo.cs b/SiMay.Net.SessionProvider/Properties/AssemblyInfo.cs deleted file mode 100644 index 2cd07b6..0000000 --- a/SiMay.Net.SessionProvider/Properties/AssemblyInfo.cs +++ /dev/null @@ -1,36 +0,0 @@ -using System.Reflection; -using System.Runtime.CompilerServices; -using System.Runtime.InteropServices; - -// 有关程序集的一般信息由以下 -// 控制。更改这些特性值可修改 -// 与程序集关联的信息。 -[assembly: AssemblyTitle("SiMay.Net.SessionProvider")] -[assembly: AssemblyDescription("")] -[assembly: AssemblyConfiguration("")] -[assembly: AssemblyCompany("")] -[assembly: AssemblyProduct("SiMay.Net.SessionProvider")] -[assembly: AssemblyCopyright("Copyright © 2019")] -[assembly: AssemblyTrademark("")] -[assembly: AssemblyCulture("")] - -// 将 ComVisible 设置为 false 会使此程序集中的类型 -//对 COM 组件不可见。如果需要从 COM 访问此程序集中的类型 -//请将此类型的 ComVisible 特性设置为 true。 -[assembly: ComVisible(false)] - -// 如果此项目向 COM 公开,则下列 GUID 用于类型库的 ID -[assembly: Guid("bf5b6f41-d688-447f-bf81-ea821216f188")] - -// 程序集的版本信息由下列四个值组成: -// -// 主版本 -// 次版本 -// 生成号 -// 修订号 -// -// 可以指定所有值,也可以使用以下所示的 "*" 预置版本号和修订号 -//通过使用 "*",如下所示: -// [assembly: AssemblyVersion("1.0.*")] -[assembly: AssemblyVersion("1.0.0.0")] -[assembly: AssemblyFileVersion("1.0.0.0")] diff --git a/SiMay.Net.SessionProvider/Providers/TcpProxySessionProviderHandle.cs b/SiMay.Net.SessionProvider/Providers/TcpProxySessionProviderHandle.cs index f9f0614..ff5bc44 100644 --- a/SiMay.Net.SessionProvider/Providers/TcpProxySessionProviderHandle.cs +++ b/SiMay.Net.SessionProvider/Providers/TcpProxySessionProviderHandle.cs @@ -12,14 +12,13 @@ using System.Threading.Tasks; using System.Threading; using SiMay.Net.SessionProvider.Core; using System.Runtime.InteropServices; -using System.Windows.Forms; using SiMay.Net.SessionProvider.Notify; using SiMay.Basic; using SiMay.Sockets.Tcp.Session; using SiMay.Sockets.Tcp.TcpConfiguration; using SiMay.Core.Packets; using SiMay.Core.Enums; -using static SiMay.Serialize.PacketSerializeHelper; +using static SiMay.Serialize.Standard.PacketSerializeHelper; namespace SiMay.Net.SessionProvider.Providers { @@ -100,7 +99,7 @@ namespace SiMay.Net.SessionProvider.Providers }; //获取所有主连接 - MessageHelper.SendMessage(session, MsgCommand.Msg_Pull_Session); + MessageHelper.SendMessage(session, MessageHead.Msg_Pull_Session); } else { @@ -257,25 +256,25 @@ namespace SiMay.Net.SessionProvider.Providers } private void OnMessage(byte[] data) { - MsgCommand cmd = (MsgCommand)data[0]; + MessageHead cmd = (MessageHead)data[0]; switch (cmd) { - case MsgCommand.Msg_Set_Session: + case MessageHead.Msg_Set_Session: this.CreateSession(data); break; - case MsgCommand.Msg_Connect_Work: + case MessageHead.Msg_Connect_Work: this._clientAgent.ConnectToServer(this._options.ServiceIPEndPoint); break; - case MsgCommand.Msg_LogOut: + case MessageHead.Msg_LogOut: this.LogOut(); break; - case MsgCommand.Msg_MessageData: + case MessageHead.Msg_MessageData: this.ProcessPackage(data); break; - case MsgCommand.Msg_Close_Session: + case MessageHead.Msg_Close_Session: this.ProcessSessionClose(data); break; - case MsgCommand.Msg_AccessKeyWrong: + case MessageHead.Msg_AccessKeyWrong: this.ProcessAccessKeyWrong(); break; } @@ -386,7 +385,7 @@ namespace SiMay.Net.SessionProvider.Providers //Array.Copy(sessionId, 0, sessionIds, i * (sizeof(Int64) + sizeof(Int64)), sizeof(Int64) + sizeof(Int64)); } - MessageHelper.SendMessage(_managerSession, MsgCommand.Msg_Set_Session_Id, buffer.ToArray()); + MessageHelper.SendMessage(_managerSession, MessageHead.Msg_Set_Session_Id, buffer.ToArray()); this._tcpProxySessionList.AddRange(sessionList.ToArray()); diff --git a/SiMay.Net.SessionProvider/SessionBased/TcpProxySessionBased.cs b/SiMay.Net.SessionProvider/SessionBased/TcpProxySessionBased.cs index 5a845a2..377eb2c 100644 --- a/SiMay.Net.SessionProvider/SessionBased/TcpProxySessionBased.cs +++ b/SiMay.Net.SessionProvider/SessionBased/TcpProxySessionBased.cs @@ -66,7 +66,7 @@ namespace SiMay.Net.SessionProvider.SessionBased BitConverter.GetBytes(bytes.Length).CopyTo(body, 8); bytes.CopyTo(body, 12); - MessageHelper.SendMessage(_session, MsgCommand.Msg_MessageData, body); + MessageHelper.SendMessage(_session, MessageHead.Msg_MessageData, body); } else { @@ -85,7 +85,7 @@ namespace SiMay.Net.SessionProvider.SessionBased if ((SessionWorkType)_session.AppTokens[0] == SessionWorkType.ManagerSession) { - MessageHelper.SendMessage(_session, MsgCommand.Msg_Close_Session, BitConverter.GetBytes(this.RemoteId)); + MessageHelper.SendMessage(_session, MessageHead.Msg_Close_Session, BitConverter.GetBytes(this.RemoteId)); } else { diff --git a/SiMay.Net.SessionProvider/SiMay.Net.SessionProvider.csproj b/SiMay.Net.SessionProvider/SiMay.Net.SessionProvider.csproj index e422d44..1b64440 100644 --- a/SiMay.Net.SessionProvider/SiMay.Net.SessionProvider.csproj +++ b/SiMay.Net.SessionProvider/SiMay.Net.SessionProvider.csproj @@ -1,88 +1,15 @@ - - - + + - Debug - AnyCPU - {BF5B6F41-D688-447F-BF81-EA821216F188} - Library - Properties - SiMay.Net.SessionProvider - SiMay.Net.SessionProvider - v4.6.1 - 512 - + netstandard2.0 - - true - full - false - bin\Debug\ - DEBUG;TRACE - prompt - 4 - 8.0 - false - - - pdbonly - true - bin\Release\ - TRACE - prompt - 4 - 8.0 - false - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + - - {B30CD716-698A-4DA2-BD1A-C152B16993C0} - SiMay.Basic - - - {1aadc6f7-6ff9-4c68-8a26-e507f22b9060} - SiMay.Core - - - {8bfdb408-d26d-4689-b426-be45ad195880} - SiMay.Net.SessionProvider.Core - - - {4888d6bb-46d9-4519-8758-e13e397aa226} - SiMay.Serialize - - - {866f8fe0-ee58-4d38-8be7-cbdd19dd1b40} - SiMay.Sockets.Standard - + + + + + - - \ No newline at end of file + + diff --git a/SiMay.Net.SessionProvider/SiMay.Net.SessionProvider.rar b/SiMay.Net.SessionProvider/SiMay.Net.SessionProvider.rar deleted file mode 100644 index 71f05b3cc62f899e4a6fdc39ca68ea80aad71a51..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 91395 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%0Dt?(TvG|8v>NWm##?}k46>@3Rl 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 SGXHyLFO#{dE5Rdx;QkK`3(BSd diff --git a/SiMay.Net.SessionProviderService/App.config b/SiMay.Net.SessionProviderService/App.config index bae5d6d..ecdcf8a 100644 --- a/SiMay.Net.SessionProviderService/App.config +++ b/SiMay.Net.SessionProviderService/App.config @@ -1,6 +1,6 @@ - + diff --git a/SiMay.Net.SessionProviderService/Properties/Settings.Designer.cs b/SiMay.Net.SessionProviderService/Properties/Settings.Designer.cs index 48d13cf..cfdd0f5 100644 --- a/SiMay.Net.SessionProviderService/Properties/Settings.Designer.cs +++ b/SiMay.Net.SessionProviderService/Properties/Settings.Designer.cs @@ -12,7 +12,7 @@ namespace SiMay.Net.SessionProviderService.Properties { [global::System.Runtime.CompilerServices.CompilerGeneratedAttribute()] - [global::System.CodeDom.Compiler.GeneratedCodeAttribute("Microsoft.VisualStudio.Editors.SettingsDesigner.SettingsSingleFileGenerator", "15.9.0.0")] + [global::System.CodeDom.Compiler.GeneratedCodeAttribute("Microsoft.VisualStudio.Editors.SettingsDesigner.SettingsSingleFileGenerator", "16.3.0.0")] internal sealed partial class Settings : global::System.Configuration.ApplicationSettingsBase { private static Settings defaultInstance = ((Settings)(global::System.Configuration.ApplicationSettingsBase.Synchronized(new Settings()))); diff --git a/SiMay.Net.SessionProviderService/SiMay.Net.SessionProviderService.csproj b/SiMay.Net.SessionProviderService/SiMay.Net.SessionProviderService.csproj index 2424346..ae880e4 100644 --- a/SiMay.Net.SessionProviderService/SiMay.Net.SessionProviderService.csproj +++ b/SiMay.Net.SessionProviderService/SiMay.Net.SessionProviderService.csproj @@ -8,7 +8,7 @@ WinExe SiMay.Net.SessionProviderService SiMay.Net.SessionProviderService - v4.6.1 + v4.7.2 512 true @@ -105,13 +105,9 @@ - {B30CD716-698A-4DA2-BD1A-C152B16993C0} + {8F2F35CB-D5EE-4D92-B42F-BCFFBF9C9D4F} SiMay.Basic - - {8BFDB408-D26D-4689-B426-BE45AD195880} - SiMay.Net.SessionProvider.Core - {866f8fe0-ee58-4d38-8be7-cbdd19dd1b40} SiMay.Sockets.Standard diff --git a/SiMay.Net.SessionProviderServiceCore/ApplicationConfiguartion.cs b/SiMay.Net.SessionProviderServiceCore/ApplicationConfiguartion.cs new file mode 100644 index 0000000..5505cf7 --- /dev/null +++ b/SiMay.Net.SessionProviderServiceCore/ApplicationConfiguartion.cs @@ -0,0 +1,39 @@ +using System; +using System.Collections.Generic; +using System.Text; + +namespace SiMay.Net.SessionProviderServiceCore +{ + public class ApplicationConfiguartion + { + /// + /// 监听地址 + /// + public static string LocalAddress { get; set; } + + /// + /// 监听端口 + /// + public static int ServicePort { get; set; } + + /// + /// 最大数据包长度 + /// + public static long MaxPacketSize { get; set; } + + /// + /// 允许主控端匿名登陆 + /// + public static bool MainApplicationAnonymous { get; set; } + + /// + /// 允许登陆的主控端Id + /// + public static long[] MainApplicationAllowAccessId { get; set; } + + /// + /// 连接AccessKey(包含主控端) + /// + public static int AccessKey { get; set; } + } +} diff --git a/SiMay.Net.SessionProviderServiceCore/Dispatcher/ApportionDispatcher.cs b/SiMay.Net.SessionProviderServiceCore/Dispatcher/ApportionDispatcher.cs new file mode 100644 index 0000000..b3fa8fc --- /dev/null +++ b/SiMay.Net.SessionProviderServiceCore/Dispatcher/ApportionDispatcher.cs @@ -0,0 +1,127 @@ +using SiMay.Basic; +using SiMay.Net.SessionProvider.Core; +using SiMay.Serialize.Standard; +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; + +namespace SiMay.Net.SessionProviderServiceCore +{ + /// + /// 连接分配器 + /// + public class ApportionDispatcher : DispatcherBase + { + private const Int16 ACK_HEAD = 1000; + + public event Action ApportionTypeHandlerEvent; + + private byte[] _ackRetainPacketData; + private long _accessId; + public override void OnMessage() + { + var defineHeadSize = sizeof(int); + if (ListByteBuffer.Count < defineHeadSize) + return; + + byte[] lenBytes = ListByteBuffer.GetRange(0, defineHeadSize).ToArray(); + int packageLen = BitConverter.ToInt32(lenBytes, 0); + + if (packageLen < 0 || packageLen > ApplicationConfiguartion.MaxPacketSize || packageLen < 25) //数据不合法 或 小于大概ack固定长度 + { + this.CloseSession(); + return; + } + + if (packageLen > ListByteBuffer.Count - defineHeadSize) + return; + + this._ackRetainPacketData = ListByteBuffer.GetRange(0, defineHeadSize + packageLen).ToArray(); + ListByteBuffer.RemoveRange(0, packageLen + defineHeadSize); + + this._accessId = BitConverter.ToInt64(_ackRetainPacketData, defineHeadSize); + + var longSize = sizeof(long); + var packageBody = GZipHelper.Decompress(_ackRetainPacketData, defineHeadSize + longSize, _ackRetainPacketData.Length - defineHeadSize - longSize); + var messageHead = TakeMessageHead(packageBody); + if (messageHead == ACK_HEAD) + { + var ack = PacketSerializeHelper.DeserializePacket(TakeMessage(packageBody)); + if (ValidityAccessIdWithKey(ack.Type, ack.AccessId, ack.AccessKey)) + this.ApportionTypeHandlerEvent?.Invoke(this, ack.Type); + else + this.CloseSession(); + } + else + this.CloseSession(); + + } + + /// + /// 验证是否允许连接 + /// + /// + /// + /// + /// + private bool ValidityAccessIdWithKey(ConnectionWorkType type, long id, long key) + { + if (type == ConnectionWorkType.MainApplicationConnection && + ApplicationConfiguartion.MainApplicationAnonymous && + key.Equals(ApplicationConfiguartion.AccessKey)) + return true;//主控端允许匿名Id登陆 + + else if (type == ConnectionWorkType.MainApplicationConnection && + !ApplicationConfiguartion.MainApplicationAnonymous && + ApplicationConfiguartion.MainApplicationAllowAccessId.Contains(id) && + ApplicationConfiguartion.AccessKey.Equals(key)) + return true; + else + { + return key.Equals(ApplicationConfiguartion.AccessKey);//其他的暂仅验证AccessKey + } + } + + /// + /// 获取被控服务AccessId + /// + /// + public long GetAccessId() + { + if (_ackRetainPacketData.IsNull()) + throw new ArgumentNullException(); + + return _accessId; + } + + /// + /// 获取Ack数据 + /// + /// + public byte[] GetACKPacketData() + { + if (_ackRetainPacketData.IsNull()) + throw new ArgumentNullException(); + + return _ackRetainPacketData; + } + + private Int16 TakeMessageHead(byte[] data) + { + return BitConverter.ToInt16(data, 0); + } + private byte[] TakeMessage(byte[] data) + { + var defineHeadSize = sizeof(Int16); + byte[] payload = new byte[data.Length - defineHeadSize]; + Array.Copy(data, defineHeadSize, payload, 0, data.Length - defineHeadSize); + return payload; + } + + public override void OnClosed() + { + + } + } +} diff --git a/SiMay.Net.SessionProviderServiceCore/Dispatcher/TcpSessionApplicationWorkerConnection.cs b/SiMay.Net.SessionProviderServiceCore/Dispatcher/TcpSessionApplicationWorkerConnection.cs new file mode 100644 index 0000000..6e416a1 --- /dev/null +++ b/SiMay.Net.SessionProviderServiceCore/Dispatcher/TcpSessionApplicationWorkerConnection.cs @@ -0,0 +1,39 @@ +using System; +using System.Collections.Generic; +using System.Text; +using SiMay.Net.SessionProvider.Core; + +namespace SiMay.Net.SessionProviderServiceCore +{ + public class TcpSessionApplicationWorkerConnection : TcpSessionChannelDispatcher + { + /// + /// 是否已与工作连接关联 + /// + public bool IsJoin { get; private set; } + + private TcpSessionApplicationWorkerConnection _targetConnection; + + public void Join(TcpSessionApplicationWorkerConnection targetConnection) + { + if (IsJoin) + return; + IsJoin = true; + _targetConnection = targetConnection; + targetConnection.Join(this); + } + public override void OnMessage() + { + if (ListByteBuffer.Count > 0) + { + this._targetConnection.SendTo(ListByteBuffer.ToArray()); + ListByteBuffer.Clear(); + } + } + public override void OnClosed() + { + _targetConnection.CloseSession(); + ListByteBuffer.Clear(); + } + } +} diff --git a/SiMay.Net.SessionProviderServiceCore/Dispatcher/TcpSessionMainApplicationConnection.cs b/SiMay.Net.SessionProviderServiceCore/Dispatcher/TcpSessionMainApplicationConnection.cs new file mode 100644 index 0000000..2dd28dd --- /dev/null +++ b/SiMay.Net.SessionProviderServiceCore/Dispatcher/TcpSessionMainApplicationConnection.cs @@ -0,0 +1,96 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using SiMay.Basic; +using SiMay.Net.SessionProvider.Core; + +namespace SiMay.Net.SessionProviderServiceCore +{ + public class TcpSessionMainApplicationConnection : TcpSessionChannelDispatcher + { + public override ConnectionWorkType ConnectionWorkType => ConnectionWorkType.MainApplicationConnection; + + private readonly IDictionary _dispatchers; + public TcpSessionMainApplicationConnection(IDictionary dispatchers) + { + _dispatchers = dispatchers; + } + + public override void OnMessage() + { + int defineHeadSize = sizeof(int); + do + { + if (ListByteBuffer.Count < defineHeadSize) + return; + + byte[] lenBytes = ListByteBuffer.GetRange(0, defineHeadSize).ToArray(); + int packageLen = BitConverter.ToInt32(lenBytes, 0); + + if (packageLen > ListByteBuffer.Count + defineHeadSize) + return; + + byte[] data = ListByteBuffer.GetRange(defineHeadSize, packageLen).ToArray(); + + this.MessageHandler(data); + ListByteBuffer.RemoveRange(0, packageLen + defineHeadSize); + + } while (ListByteBuffer.Count > defineHeadSize); + } + + private void MessageHandler(byte[] data) + { + + switch (data.GetMessageHead()) + { + case MessageHead.APP_PULL_SESSION: + this.GetAllSessionItem(); + break; + case MessageHead.APP_MESSAGE_DATA: + var message = data.GetMessageEntity(); + this.TranspondMessage(message.DispatcherId, message.Data); + break; + default: + break; + } + } + + /// + /// 获取所有主服务连接 + /// + private void GetAllSessionItem() + { + var mainServiceConnections = _dispatchers + .Select(c => c.Value) + .Where(c => c.ConnectionWorkType == ConnectionWorkType.MainServiceConnection) + .Cast() + .ToList(); + + var data = MessageHelper.CopyMessageHeadTo(MessageHead.MID_SESSION, + new SessionPacket() + { + SessionItems = mainServiceConnections.Select(c => new SessionItemPacket() + { + Id = c.DispatcherId, + ACKPacketData = c.ACKPacketData + }).ToArray() + }); + SendTo(data); + } + + private void TranspondMessage(long dispatcherId, byte[] data) + { + TcpSessionChannelDispatcher dispatcher; + if (_dispatchers.TryGetValue(dispatcherId, out dispatcher)) + { + dispatcher.SendTo(data);//直接转发 + } + } + + public override void OnClosed() + { + + } + } +} diff --git a/SiMay.Net.SessionProviderServiceCore/Dispatcher/TcpSessionMainConnection.cs b/SiMay.Net.SessionProviderServiceCore/Dispatcher/TcpSessionMainConnection.cs new file mode 100644 index 0000000..1062586 --- /dev/null +++ b/SiMay.Net.SessionProviderServiceCore/Dispatcher/TcpSessionMainConnection.cs @@ -0,0 +1,84 @@ +using SiMay.Net.SessionProvider.Core; +using System; +using System.Collections.Concurrent; +using System.Collections.Generic; +using System.Text; + +namespace SiMay.Net.SessionProviderServiceCore +{ + public class TcpSessionMainConnection : TcpSessionChannelDispatcher + { + public override ConnectionWorkType ConnectionWorkType => ConnectionWorkType.MainServiceConnection; + + private readonly object _sendLock = new object(); + private readonly IDictionary _dispatchers; + public TcpSessionMainConnection(IDictionary dispatchers) + { + _dispatchers = dispatchers; + } + + public byte[] ACKPacketData { get; set; } + + long? _accessId; + int? _packageLength; + int _transpondOffset; + public override void OnMessage() + { + int defineHeadSize = sizeof(int); + int defineAccessIdSize = sizeof(long); + do + { + if (!_accessId.HasValue && !_packageLength.HasValue) + { + if (ListByteBuffer.Count < defineHeadSize + defineAccessIdSize) + break; + + byte[] headBytes = ListByteBuffer.GetRange(0, defineHeadSize + defineAccessIdSize).ToArray(); + this._packageLength = BitConverter.ToInt32(headBytes, 0); + this._accessId = BitConverter.ToInt64(headBytes, defineHeadSize); + this._transpondOffset = 0; + } + + TcpSessionChannelDispatcher dispatcher; + if (_dispatchers.TryGetValue((int)_accessId.Value, out dispatcher) || true) + { + var calculateOffsetLength = (_packageLength.Value + defineHeadSize) - _transpondOffset; + if (ListByteBuffer.Count <= calculateOffsetLength) + calculateOffsetLength = ListByteBuffer.Count; + + var data = ListByteBuffer.GetRange(0, calculateOffsetLength).ToArray(); + + dispatcher?.SendTo(MessageHelper.CopyMessageHeadTo(MessageHead.MID_MESSAGE_DATA, + new MessageDataPacket() + { + AccessId = dispatcher.DispatcherId, + DispatcherId = this.DispatcherId, + Data = data + })); + + this._transpondOffset += data.Length; + if (_transpondOffset == _packageLength) + { + this._accessId = null; this._packageLength = null; + } + + ListByteBuffer.RemoveRange(0, calculateOffsetLength); + } + } while (ListByteBuffer.Count > defineHeadSize + defineAccessIdSize); + } + + public override void SendTo(byte[] data) + { + //防止其他线程发送消息 + lock (this._sendLock) + { + base.SendTo(data); + } + } + + public override void OnClosed() + { + + } + } +} diff --git a/SiMay.Net.SessionProviderServiceCore/DispatcherBase/DispatcherBase.cs b/SiMay.Net.SessionProviderServiceCore/DispatcherBase/DispatcherBase.cs new file mode 100644 index 0000000..1985698 --- /dev/null +++ b/SiMay.Net.SessionProviderServiceCore/DispatcherBase/DispatcherBase.cs @@ -0,0 +1,107 @@ +using SiMay.Net.SessionProvider.Core; +using SiMay.Sockets.Tcp.Session; +using System; +using System.Collections.Generic; + +namespace SiMay.Net.SessionProviderServiceCore +{ + public abstract class DispatcherBase : IDisposable + { + /// + /// 当前连接会话 + /// + protected TcpSocketSaeaSession CurrentSession + { + get; + set; + } + + private long? _dispatcherId; + + /// + /// Id + /// + public virtual long DispatcherId + { + get + { + if (_dispatcherId.HasValue) + return _dispatcherId.Value; + else + { + _dispatcherId = this.GetHashCode(); + return _dispatcherId.Value; + } + } + set + { + _dispatcherId = value; + } + } + + /// + /// 连接工作类型 + /// + public virtual ConnectionWorkType ConnectionWorkType + { + get; + set; + } = ConnectionWorkType.None; + + /// + /// 缓冲区 + /// + public List ListByteBuffer + { + get; + set; + } = new List(); + + /// + /// 设置连接会话 + /// + /// + public virtual void SetSession(TcpSocketSaeaSession session) + { + CurrentSession = session; + + session.AppTokens = new object[] + { + this, + ConnectionWorkType + }; + } + + /// + /// 获取当前会话 + /// + public TcpSocketSaeaSession GetCurrentSession() + { + return CurrentSession; + } + + /// + /// 关闭当前会话 + /// + public virtual void CloseSession() + { + CurrentSession.Close(true); + } + + /// + /// 触发消息处理 + /// + public abstract void OnMessage(); + + /// + /// 会话关闭 + /// + public abstract void OnClosed(); + + + public virtual void Dispose() + { + ListByteBuffer.Clear(); + } + } +} diff --git a/SiMay.Net.SessionProviderServiceCore/DispatcherBase/TcpSessionChannelDispatcher.cs b/SiMay.Net.SessionProviderServiceCore/DispatcherBase/TcpSessionChannelDispatcher.cs new file mode 100644 index 0000000..dc3e5dd --- /dev/null +++ b/SiMay.Net.SessionProviderServiceCore/DispatcherBase/TcpSessionChannelDispatcher.cs @@ -0,0 +1,14 @@ +using System; +using System.Collections.Generic; +using System.Text; + +namespace SiMay.Net.SessionProviderServiceCore +{ + public abstract class TcpSessionChannelDispatcher : DispatcherBase + { + public virtual void SendTo(byte[] data) + { + CurrentSession.SendAsync(data); + } + } +} diff --git a/SiMay.Net.SessionProviderServiceCore/Extension/CreateDispatcherExtension.cs b/SiMay.Net.SessionProviderServiceCore/Extension/CreateDispatcherExtension.cs new file mode 100644 index 0000000..1902ac3 --- /dev/null +++ b/SiMay.Net.SessionProviderServiceCore/Extension/CreateDispatcherExtension.cs @@ -0,0 +1,53 @@ +using SiMay.Net.SessionProvider.Core; +using System; +using System.Collections.Concurrent; +using System.Collections.Generic; +using System.Text; + +namespace SiMay.Net.SessionProviderServiceCore +{ + public static class CreateDispatcherExtension + { + public static TcpSessionMainConnection CreateMainServiceChannelDispatcher(this ApportionDispatcher apportionDispatcher, IDictionary dispatchers) + { + var mainServiceChannelDispatcher = new TcpSessionMainConnection(dispatchers); + mainServiceChannelDispatcher.ACKPacketData = apportionDispatcher.GetACKPacketData(); + mainServiceChannelDispatcher.SetSession(apportionDispatcher.GetCurrentSession()); + var bufferData = apportionDispatcher.ListByteBuffer.ToArray(); + if (bufferData.Length > 0)//如缓冲区有数据,则处理消息 + { + mainServiceChannelDispatcher.ListByteBuffer.AddRange(bufferData); + mainServiceChannelDispatcher.OnMessage(); + } + return mainServiceChannelDispatcher; + } + + public static TcpSessionMainApplicationConnection CreateMainApplicationChannelDispatcher(this ApportionDispatcher apportionDispatcher, IDictionary dispatchers) + { + var accessId = apportionDispatcher.GetAccessId(); + var mainappChannelDispatcher = new TcpSessionMainApplicationConnection(dispatchers); + mainappChannelDispatcher.DispatcherId = accessId; + mainappChannelDispatcher.SetSession(apportionDispatcher.GetCurrentSession()); + + var bufferData = apportionDispatcher.ListByteBuffer.ToArray(); + if (bufferData.Length > 0)//如缓冲区有数据,则处理消息 + { + mainappChannelDispatcher.ListByteBuffer.AddRange(bufferData); + mainappChannelDispatcher.OnMessage(); + } + return mainappChannelDispatcher; + } + + public static TcpSessionApplicationWorkerConnection CreateApplicationWorkerChannelDispatcher(this ApportionDispatcher apportionDispatcher, IDictionary dispatchers, ConnectionWorkType workType) + { + var workerConnection = new TcpSessionApplicationWorkerConnection(); + workerConnection.ConnectionWorkType = workType; + workerConnection.SetSession(apportionDispatcher.GetCurrentSession()); + + var bufferData = apportionDispatcher.ListByteBuffer.ToArray(); + if (bufferData.Length > 0)//如缓冲区有数据,则处理消息 + workerConnection.ListByteBuffer.AddRange(bufferData); + return workerConnection; + } + } +} diff --git a/SiMay.Net.SessionProviderServiceCore/MainSessionProviderService.cs b/SiMay.Net.SessionProviderServiceCore/MainSessionProviderService.cs new file mode 100644 index 0000000..2fbebc9 --- /dev/null +++ b/SiMay.Net.SessionProviderServiceCore/MainSessionProviderService.cs @@ -0,0 +1,205 @@ +using SiMay.Basic; +using SiMay.Net.SessionProvider.Core; +using SiMay.Sockets.Tcp; +using SiMay.Sockets.Tcp.Server; +using SiMay.Sockets.Tcp.Session; +using SiMay.Sockets.Tcp.TcpConfiguration; +using System; +using System.Collections.Generic; +using System.Linq; +using System.Net; + +namespace SiMay.Net.SessionProviderServiceCore +{ + public class MainSessionProviderService + { + + /// + /// 日志输出 + /// + public event Action LogOutputEventHandler; + + private TcpSocketSaeaServer _tcpSaeaServer; + private IList> _appServiceChannels = new List>(); + private IDictionary _dispatchers = new Dictionary(); + public bool StartService() + { + var serverConfig = new TcpSocketSaeaServerConfiguration(); + serverConfig.ReuseAddress = false; + serverConfig.KeepAlive = true; + serverConfig.KeepAliveInterval = 5000; + serverConfig.KeepAliveSpanTime = 1000; + serverConfig.PendingConnectionBacklog = 0; + + var ipe = new IPEndPoint(IPAddress.Parse(ApplicationConfiguartion.LocalAddress), ApplicationConfiguartion.ServicePort); + + _tcpSaeaServer = TcpSocketsFactory.CreateServerAgent(TcpSocketSaeaSessionType.Full, serverConfig, (notify, session) => + { + switch (notify) + { + case TcpSocketCompletionNotify.OnConnected: + + ApportionDispatcher apportionDispatcher = new ApportionDispatcher(); + apportionDispatcher.ApportionTypeHandlerEvent += ApportionTypeHandlerEvent; + apportionDispatcher.SetSession(session); + + break; + case TcpSocketCompletionNotify.OnSend: + break; + case TcpSocketCompletionNotify.OnDataReceiveing: + this.OnDataReceiveingHandler(session); + break; + case TcpSocketCompletionNotify.OnClosed: + this.OnClosedHandler(session); + break; + default: + break; + } + + }); + return true; + } + + private void OnDataReceiveingHandler(TcpSocketSaeaSession session) + { + byte[] data = new byte[session.ReceiveBytesTransferred]; + Array.Copy(session.CompletedBuffer, 0, data, 0, data.Length); + + var dispatcher = session.AppTokens[SysContanct.INDEX_WORKER].ConvertTo(); + dispatcher.ListByteBuffer.AddRange(data); + dispatcher.OnMessage(); + } + + private void OnClosedHandler(TcpSocketSaeaSession session) + { + var closedDispatcher = session.AppTokens[SysContanct.INDEX_WORKER].ConvertTo(); + closedDispatcher.OnClosed(); + + if (closedDispatcher.ConnectionWorkType == ConnectionWorkType.MainServiceConnection) + { + var data = MessageHelper.CopyMessageHeadTo(MessageHead.MID_SESSION_CLOSED, + new SessionClosedPacket() + { + Id = closedDispatcher.DispatcherId + }); + + //通知所有主控端离线 + _dispatchers + .Select(c => c.Value) + .Where(c => c.ConnectionWorkType == ConnectionWorkType.MainApplicationConnection) + .ForEach(c => c.SendTo(data)); + } + + var serviceWorkerChannelItem = this._appServiceChannels.FirstOrDefault(c => c.Item2 == closedDispatcher.DispatcherId); + if (!serviceWorkerChannelItem.IsNull()) + _appServiceChannels.Remove(serviceWorkerChannelItem); + + if (_dispatchers.ContainsKey(closedDispatcher.DispatcherId)) + _dispatchers.Remove(closedDispatcher.DispatcherId); + } + + private void ApportionTypeHandlerEvent(ApportionDispatcher apportionDispatcher, ConnectionWorkType type) + { + switch (type) + { + case ConnectionWorkType.MainServiceConnection: + this.MainServiceConnect(apportionDispatcher); + break; + case ConnectionWorkType.MainApplicationConnection: + this.MainApplicationConnect(apportionDispatcher); + break; + case ConnectionWorkType.ApplicationServiceConnection: + this.ApplicationServiceConnect(apportionDispatcher); + break; + case ConnectionWorkType.ApplicationConnection: + this.ApplicationConnect(apportionDispatcher); + break; + case ConnectionWorkType.None: + break; + default: + break; + } + } + + private void MainServiceConnect(ApportionDispatcher apportionDispatcher) + { + var mainServiceChannelDispatcher = apportionDispatcher.CreateMainServiceChannelDispatcher(_dispatchers); + + var data = MessageHelper.CopyMessageHeadTo(MessageHead.MID_SESSION, + new SessionPacket() + { + SessionItems = new SessionItemPacket[] + { + new SessionItemPacket(){ + Id = mainServiceChannelDispatcher.DispatcherId, + ACKPacketData = mainServiceChannelDispatcher.ACKPacketData + } + } + }); + //通知所有主控端上线 + _dispatchers + .Select(c => c.Value) + .Where(c => c.ConnectionWorkType == ConnectionWorkType.MainApplicationConnection) + .ForEach(c => c.SendTo(data)); + + _dispatchers.Add(mainServiceChannelDispatcher.DispatcherId, mainServiceChannelDispatcher); + } + + private void MainApplicationConnect(ApportionDispatcher apportionDispatcher) + { + var accessId = apportionDispatcher.GetAccessId(); + var mainappChannelDispatcher = apportionDispatcher.CreateMainApplicationChannelDispatcher(_dispatchers); + if (!_dispatchers.ContainsKey(accessId))//可能重连太快 + { + //主控端使用自身AccessId作索引 + _dispatchers.Add(accessId, mainappChannelDispatcher); + } + else + { + var aboutOfCloseDispatcher = _dispatchers[accessId]; + + var data = MessageHelper.CopyMessageHeadTo(MessageHead.MID_LOGOUT, + new LogOutPacket() + { + Message = "已有相同Id的主控端登陆,你已被登出!" + }); + aboutOfCloseDispatcher.SendTo(data); + aboutOfCloseDispatcher.CloseSession(); + } + } + + private void ApplicationServiceConnect(ApportionDispatcher apportionDispatcher) + { + //找到相应主控端连接 + TcpSessionChannelDispatcher dispatcher; + if (_dispatchers.TryGetValue(apportionDispatcher.GetAccessId(), out dispatcher)) + { + var appWorkerConnectionDispatcher = apportionDispatcher.CreateApplicationWorkerChannelDispatcher(_dispatchers, ConnectionWorkType.ApplicationServiceConnection); + this._appServiceChannels.Add(new Tuple(apportionDispatcher.GetAccessId(), appWorkerConnectionDispatcher.DispatcherId)); + + var data = MessageHelper.CopyMessageHeadTo(MessageHead.MID_APPWORK); + dispatcher.SendTo(data); + } + } + + private void ApplicationConnect(ApportionDispatcher apportionDispatcher) + { + TcpSessionChannelDispatcher dispatcher; + var serviceWorkerChannelItem = this._appServiceChannels.FirstOrDefault(c => c.Item1 == apportionDispatcher.GetAccessId()); + if (!serviceWorkerChannelItem.IsNull() && _dispatchers.TryGetValue(serviceWorkerChannelItem.Item2, out dispatcher)) + { + var serviceChannelDispatcher = dispatcher.ConvertTo(); + var appChannelDispatcher = apportionDispatcher.CreateApplicationWorkerChannelDispatcher(_dispatchers, ConnectionWorkType.ApplicationConnection); + if (!serviceChannelDispatcher.IsJoin) + { + serviceChannelDispatcher.Join(appChannelDispatcher); + serviceChannelDispatcher.OnMessage(); + appChannelDispatcher.OnMessage(); + } + this._appServiceChannels.Remove(serviceWorkerChannelItem); + + _dispatchers.Add(appChannelDispatcher.DispatcherId, appChannelDispatcher); + } + } + } +} diff --git a/SiMay.Net.SessionProviderServiceCore/SiMay.Net.SessionProviderServiceCore.csproj b/SiMay.Net.SessionProviderServiceCore/SiMay.Net.SessionProviderServiceCore.csproj new file mode 100644 index 0000000..ddd3503 --- /dev/null +++ b/SiMay.Net.SessionProviderServiceCore/SiMay.Net.SessionProviderServiceCore.csproj @@ -0,0 +1,14 @@ + + + + netstandard2.0 + + + + + + + + + + diff --git a/SiMay.Net.SessionProviderServiceCore/SysContanct.cs b/SiMay.Net.SessionProviderServiceCore/SysContanct.cs new file mode 100644 index 0000000..54ebdb1 --- /dev/null +++ b/SiMay.Net.SessionProviderServiceCore/SysContanct.cs @@ -0,0 +1,12 @@ +using System; +using System.Collections.Generic; +using System.Text; + +namespace SiMay.Net.SessionProviderServiceCore +{ + public class SysContanct + { + public const int INDEX_WORKER = 0; + public const int INDEX_WORKTYPE = 1; + } +} diff --git a/SiMay.RemoteClient.NewCore/ApplicationService/ScreenService.cs b/SiMay.RemoteClient.NewCore/ApplicationService/ScreenService.cs index f2733a6..369d432 100644 --- a/SiMay.RemoteClient.NewCore/ApplicationService/ScreenService.cs +++ b/SiMay.RemoteClient.NewCore/ApplicationService/ScreenService.cs @@ -115,7 +115,7 @@ namespace SiMay.ServiceCore { switch (nCode) { - case DifferStatus.FULLDIFFERENCES: + case DifferStatus.FULL_DIFFERENCES: SendTo(CurrentSession, MessageHead.C_SCREEN_DIFFBITMAP, new ScreenFragmentPack() { @@ -123,7 +123,7 @@ namespace SiMay.ServiceCore }); break; - case DifferStatus.NEXTSCREEN: + case DifferStatus.NEXT_SCREEN: SendTo(CurrentSession, MessageHead.C_SCREEN_BITMP, new ScreenFragmentPack() { @@ -131,7 +131,7 @@ namespace SiMay.ServiceCore }); break; - case DifferStatus.COMPLETE: + case DifferStatus.COMPLETED: SendTo(CurrentSession, MessageHead.C_SCREEN_SCANCOMPLETE); break; } diff --git a/SiMay.RemoteClient.NewCore/Program.cs b/SiMay.RemoteClient.NewCore/Program.cs index 8ec12b6..0b41f68 100644 --- a/SiMay.RemoteClient.NewCore/Program.cs +++ b/SiMay.RemoteClient.NewCore/Program.cs @@ -19,6 +19,7 @@ using System.Linq; using System.Reflection; using System.ServiceProcess; using SiMay.ServiceCore.MainService; +using SiMay.Serialize.Standard; namespace SiMay.ServiceCore { diff --git a/SiMay.RemoteClient.NewCore/ServiceBase/ApplicationProtocolService.cs b/SiMay.RemoteClient.NewCore/ServiceBase/ApplicationProtocolService.cs index 61a6ead..e2e1012 100644 --- a/SiMay.RemoteClient.NewCore/ServiceBase/ApplicationProtocolService.cs +++ b/SiMay.RemoteClient.NewCore/ServiceBase/ApplicationProtocolService.cs @@ -88,7 +88,7 @@ namespace SiMay.ServiceCore protected long GetAccessId(TcpSocketSaeaSession session) { - if (session.CompletedBuffer == null) + if (session.CompletedBuffer.IsNull()) return 0; return BitConverter.ToInt64(session.CompletedBuffer, 0); } diff --git a/SiMay.RemoteClient.NewCore/SiMay.ServiceCore.csproj b/SiMay.RemoteClient.NewCore/SiMay.ServiceCore.csproj index 2a5293d..242962a 100644 --- a/SiMay.RemoteClient.NewCore/SiMay.ServiceCore.csproj +++ b/SiMay.RemoteClient.NewCore/SiMay.ServiceCore.csproj @@ -211,7 +211,7 @@ - {B30CD716-698A-4DA2-BD1A-C152B16993C0} + {8f2f35cb-d5ee-4d92-b42f-bcffbf9c9d4f} SiMay.Basic @@ -222,9 +222,9 @@ {7efe8058-f772-40eb-8e12-6e88e2a9e19a} SiMay.RemoteService.Loader - - {4888d6bb-46d9-4519-8758-e13e397aa226} - SiMay.Serialize + + {9525A4AA-6731-4AB2-8CD0-ADDF7940FE32} + SiMay.Serialize.Standard {866f8fe0-ee58-4d38-8be7-cbdd19dd1b40} diff --git a/SiMay.RemoteClient.NewCore/SysUtil.cs b/SiMay.RemoteClient.NewCore/SysUtil.cs index cd7313e..bbd4dba 100644 --- a/SiMay.RemoteClient.NewCore/SysUtil.cs +++ b/SiMay.RemoteClient.NewCore/SysUtil.cs @@ -50,7 +50,7 @@ namespace SiMay.ServiceCore var aboutMenu = new ToolStripMenuItem("关于服务"); aboutMenu.MouseDown += (s, e) => { - MessageBoxHelper.ShowBoxExclamation("SiMay远程管理是一款开源的Windows系统远程协助系统,支持远程桌面、文件管理、远程语音、远程摄像头、远程注册表、远程shell等功能,您当前运行的是被控服务程序。", "关于程序"); + MessageBox.Show("SiMay远程管理是一款开源的Windows系统远程协助系统,支持远程桌面、文件管理、远程语音、远程摄像头、远程注册表、远程shell等功能,您当前运行的是被控服务程序。", "关于程序", 0, MessageBoxIcon.Exclamation); }; contextMenus.Items.Add(aboutMenu); contextMenus.Items.Add(exitMenu); diff --git a/SiMay.RemoteControlsCore/ApplicationAdapterHandler/RemoteFileAdapterHandler.cs b/SiMay.RemoteControlsCore/ApplicationAdapterHandler/RemoteFileAdapterHandler.cs index 92cead4..8a6b7a0 100644 --- a/SiMay.RemoteControlsCore/ApplicationAdapterHandler/RemoteFileAdapterHandler.cs +++ b/SiMay.RemoteControlsCore/ApplicationAdapterHandler/RemoteFileAdapterHandler.cs @@ -11,7 +11,7 @@ using SiMay.Core.PacketModelBinder.Attributes; using SiMay.Core.Packets; using SiMay.Core.Packets.FileManager; using SiMay.Net.SessionProvider.SessionBased; -using SiMay.Serialize; +using SiMay.Serialize.Standard; namespace SiMay.RemoteControlsCore.HandlerAdapters { @@ -314,7 +314,7 @@ namespace SiMay.RemoteControlsCore.HandlerAdapters var status = 0; //返回null表示已断开连接 - if (responsed == null) + if (responsed.IsNull()) { var positionNull = await this.AwaitResetDownloadFile(fileStream);//等待重新连接 if (positionNull.HasValue) @@ -348,7 +348,7 @@ namespace SiMay.RemoteControlsCore.HandlerAdapters //LogHelper.DebugWriteLog("download data:" + (data == null ? "null" : data.Data.Length.ToString())); if (this.WhetherClose) break;//传输中途关闭应用 - if (data == null) + if (data.IsNull()) { var positionNull = await this.AwaitResetDownloadFile(fileStream).ConfigureAwait(true); if (!positionNull.HasValue) @@ -463,7 +463,7 @@ namespace SiMay.RemoteControlsCore.HandlerAdapters LogHelper.DebugWriteLog("begin upload"); var responsed = await this.AwaitOpenUploadFileStatus(remoteFileName);//获取远程文件状态 - if (responsed == null)//返回null表示等待结果期间连接中断 + if (responsed.IsNull())//返回null表示等待结果期间连接中断 { var isReset = await this.AwaitResetUploadFile(); if (isReset) @@ -691,7 +691,7 @@ namespace SiMay.RemoteControlsCore.HandlerAdapters var targetFileName = file.FileName; var localFileName = file.FileName.Substring(remotedirectory.LastIndexOf("\\") + 1); var fileStream = onCreateFileStream?.Invoke(localFileName); - if (fileStream == null) + if (fileStream.IsNull()) continue; if (_transferMode == TransferMode.Cancel || TransferTaskFlage == TransferTaskFlage.Abort) break; @@ -752,7 +752,7 @@ namespace SiMay.RemoteControlsCore.HandlerAdapters this._sessionOfLinesEvent.Reset();//阻塞等待重连 this._workerStreamEvent.SetOneData();//如果有正在等待数据响应的,则先释放信号,进入重置方法 LogHelper.DebugWriteLog("close eventSet"); - if (this.WhetherClose)//如果窗口已关闭,则释放退出 + if (this.WhetherClose)//如果应用已关闭,则释放退出 this._sessionOfLinesEvent.Set(); base.SessionClosed(session); diff --git a/SiMay.RemoteControlsCore/ApplicationAdapterHandler/RemoteScreenAdapterHandler.cs b/SiMay.RemoteControlsCore/ApplicationAdapterHandler/RemoteScreenAdapterHandler.cs index 092953e..c6192a8 100644 --- a/SiMay.RemoteControlsCore/ApplicationAdapterHandler/RemoteScreenAdapterHandler.cs +++ b/SiMay.RemoteControlsCore/ApplicationAdapterHandler/RemoteScreenAdapterHandler.cs @@ -14,7 +14,7 @@ using SiMay.Core.Packets.Screen; using SiMay.Core.ScreenSpy.Entitys; using SiMay.Net.SessionProvider.SessionBased; using SiMay.RemoteControlsCore.Enum; -using static SiMay.Serialize.PacketSerializeHelper; +using static SiMay.Serialize.Standard.PacketSerializeHelper; namespace SiMay.RemoteControlsCore.HandlerAdapters { diff --git a/SiMay.RemoteControlsCore/MainApplicationAdapterHandler.cs b/SiMay.RemoteControlsCore/MainApplicationAdapterHandler.cs index dbe3f90..6ea30cc 100644 --- a/SiMay.RemoteControlsCore/MainApplicationAdapterHandler.cs +++ b/SiMay.RemoteControlsCore/MainApplicationAdapterHandler.cs @@ -69,7 +69,7 @@ namespace SiMay.RemoteControlsCore public int ViewRefreshInterval { get; set; } /// - /// 线程同步上下文 + /// 主线程同步上下文 /// public SynchronizationContext SynchronizationContext { get; set; } @@ -183,7 +183,7 @@ namespace SiMay.RemoteControlsCore else SynchronizationContext.Send(NotifyProc, null); - void NotifyProc(object val) + void NotifyProc(object @object) { try { @@ -370,7 +370,7 @@ namespace SiMay.RemoteControlsCore string identifyId = openControl.IdentifyId; //查找离线任务队列,如果有对应的任务则继续工作 var task = FindOfSuspendTaskContext(identifyId); - if (task != null) + if (!task.IsNull()) { //再发出重连命令后,如果使用者主动关闭消息处理器将不再建立连接 if (task.AdapterHandler.WhetherClose) @@ -392,7 +392,7 @@ namespace SiMay.RemoteControlsCore else { var context = SysUtil.ApplicationTypes.FirstOrDefault(x => x.ApplicationKey.Equals(appKey)); - if (context != null) + if (!context.IsNull()) { var appHandlerType = context.Type.GetAppAdapterHandlerType(); @@ -437,7 +437,7 @@ namespace SiMay.RemoteControlsCore { string macName = GetMessage(session).ToUnicodeString(); var syncContext = session.AppTokens[SysConstants.INDEX_WORKER].ConvertTo(); - syncContext.KeyDictions[SysConstants.RecordScreenIsAction] = true;//开启 + syncContext.KeyDictions[SysConstants.HasLaunchDesktopRecord] = true;//开启 syncContext.KeyDictions[SysConstants.MachineName] = macName;//标识名(用计算机名作为唯一标识) SendTo(session, MessageHead.S_MAIN_DESKTOPRECORD_GETFRAME); @@ -451,15 +451,15 @@ namespace SiMay.RemoteControlsCore private void ScreenSaveHandler(SessionProviderContext session) { var syncContext = session.AppTokens[SysConstants.INDEX_WORKER].ConvertTo(); - bool status = syncContext.KeyDictions[SysConstants.RecordScreenIsAction].ConvertTo(); - string macName = syncContext.KeyDictions[SysConstants.MachineName].ConvertTo(); + var status = syncContext.KeyDictions[SysConstants.HasLaunchDesktopRecord].ConvertTo(); + var macName = syncContext.KeyDictions[SysConstants.MachineName].ConvertTo(); - if (!Directory.Exists(Path.Combine("ScreenRecord", macName))) - Directory.CreateDirectory(Path.Combine("ScreenRecord", macName)); + if (!Directory.Exists(Path.Combine("DesktopRecord", macName))) + Directory.CreateDirectory(Path.Combine("DesktopRecord", macName)); - using (var ms = new MemoryStream(session.CompletedBuffer.GetMessagePayload())) + using (var ms = new MemoryStream(GetMessage(session))) { - string fileName = Path.Combine(Environment.CurrentDirectory, "ScreenRecord", macName, DateTime.Now.ToFileTime() + ".png"); + string fileName = Path.Combine(Environment.CurrentDirectory, "DesktopRecord", macName, DateTime.Now.ToFileTime() + ".png"); Image img = Image.FromStream(ms); img.Save(fileName); img.Dispose(); @@ -481,7 +481,7 @@ namespace SiMay.RemoteControlsCore var describePack = GetMessageEntity(session); var syncContext = session.AppTokens[SysConstants.INDEX_WORKER].ConvertTo(); var view = this.OnCreateDesktopViewHandlerEvent?.Invoke(syncContext); - if (view == null) + if (view.IsNull()) return; view.Caption = describePack.MachineName + "-(" + describePack.RemarkInformation + ")"; syncContext.KeyDictions[SysConstants.DesktopView] = view; @@ -547,7 +547,7 @@ namespace SiMay.RemoteControlsCore syncContext.KeyDictions[SysConstants.OpenScreenRecord] = login.OpenScreenRecord; syncContext.KeyDictions[SysConstants.OpenScreenWall] = login.OpenScreenWall; syncContext.KeyDictions[SysConstants.IdentifyId] = login.IdentifyId; - syncContext.KeyDictions[SysConstants.RecordScreenIsAction] = false;//桌面记录状态 + syncContext.KeyDictions[SysConstants.HasLaunchDesktopRecord] = false;//桌面记录状态 syncContext.KeyDictions[SysConstants.RecordHeight] = login.RecordHeight;//用于桌面记录的高 syncContext.KeyDictions[SysConstants.RecordWidth] = login.RecordWidth;//用于桌面记录宽 syncContext.KeyDictions[SysConstants.RecordSpanTime] = login.RecordSpanTime; @@ -591,7 +591,7 @@ namespace SiMay.RemoteControlsCore { SysConstants.OpenScreenWall, login.OpenScreenWall }, { SysConstants.IdentifyId, login.IdentifyId }, { SysConstants.OpenScreenRecord, login.OpenScreenRecord }, - { SysConstants.RecordScreenIsAction, false }, + { SysConstants.HasLaunchDesktopRecord, false }, { SysConstants.RecordHeight, login.RecordHeight }, { SysConstants.RecordWidth, login.RecordWidth }, { SysConstants.RecordSpanTime, login.RecordSpanTime }, diff --git a/SiMay.RemoteControlsCore/SiMay.RemoteControlsCore.csproj b/SiMay.RemoteControlsCore/SiMay.RemoteControlsCore.csproj index 8ac3e4c..94f0dd5 100644 --- a/SiMay.RemoteControlsCore/SiMay.RemoteControlsCore.csproj +++ b/SiMay.RemoteControlsCore/SiMay.RemoteControlsCore.csproj @@ -85,7 +85,7 @@ - {B30CD716-698A-4DA2-BD1A-C152B16993C0} + {8F2F35CB-D5EE-4D92-B42F-BCFFBF9C9D4F} SiMay.Basic @@ -93,12 +93,12 @@ SiMay.Core - {BF5B6F41-D688-447F-BF81-EA821216F188} + {71283236-56CB-481E-A644-B7F9AF9EFDF9} SiMay.Net.SessionProvider - - {4888d6bb-46d9-4519-8758-e13e397aa226} - SiMay.Serialize + + {9525A4AA-6731-4AB2-8CD0-ADDF7940FE32} + SiMay.Serialize.Standard diff --git a/SiMay.RemoteControlsCore/SysConstants.cs b/SiMay.RemoteControlsCore/SysConstants.cs index ef07ce6..10c91b1 100644 --- a/SiMay.RemoteControlsCore/SysConstants.cs +++ b/SiMay.RemoteControlsCore/SysConstants.cs @@ -28,7 +28,7 @@ namespace SiMay.RemoteControlsCore public const string OpenScreenWall = "OpenScreenWall"; public const string IdentifyId = "IdentifyId"; public const string OpenScreenRecord = "OpenScreenRecord"; - public const string RecordScreenIsAction = "RecordScreenIsAction"; + public const string HasLaunchDesktopRecord = "RecordScreenIsAction"; public const string RecordHeight = "RecordHeight"; public const string RecordWidth = "RecordWidth"; public const string RecordSpanTime = "RecordSpanTime"; diff --git a/SiMay.RemoteMonitor/Application/FileApplication.cs b/SiMay.RemoteMonitor/Application/FileApplication.cs index 58ef0c7..97239b5 100644 --- a/SiMay.RemoteMonitor/Application/FileApplication.cs +++ b/SiMay.RemoteMonitor/Application/FileApplication.cs @@ -73,20 +73,7 @@ namespace SiMay.RemoteMonitor.Application private void FileManager_Load(object sender, EventArgs e) { - this._closeTreeBtn = new Button(); - this._closeTreeBtn.Click += _closeTreeBtn_Click; - this._closeTreeBtn.Hide(); - this._closeTreeBtn.Text = "收起"; - this._closeTreeBtn.Height = 25; - this._closeTreeBtn.Width = 100; - this._remoteDirectoryTreeView = new TreeView(); - this._remoteDirectoryTreeView.ImageList = _imgList; - this._remoteDirectoryTreeView.ContextMenuStrip = this.treeContext; - this._remoteDirectoryTreeView.DoubleClick += remoteDirectoryTreeView_DoubleClick; - this._remoteDirectoryTreeView.Hide(); - this.Controls.Add(_remoteDirectoryTreeView); - this.Controls.Add(_closeTreeBtn); - this.Initialize(); + this.InitializeUI(); this.Text = this._title = this._title.Replace("#Name#", this.RemoteFileAdapterHandler.OriginName); this.RemoteFileAdapterHandler.OnRemoteExceptionEventHandler += OnRemoteExceptionEventHandler; @@ -101,7 +88,7 @@ namespace SiMay.RemoteMonitor.Application this.RemoteFileAdapterHandler.GetRemoteRootTreeItems(string.Empty); this.RemoteFileAdapterHandler.GetRemoteDriveItems(); } - private void Initialize() + private void InitializeUI() { string downPath = Path.Combine(Environment.CurrentDirectory, "download"); @@ -112,6 +99,20 @@ namespace SiMay.RemoteMonitor.Application this.fileList.SmallImageList = _imgList; this.fileList.LargeImageList = _imgList; + this._closeTreeBtn = new Button(); + this._closeTreeBtn.Click += _closeTreeBtn_Click; + this._closeTreeBtn.Hide(); + this._closeTreeBtn.Text = "收起"; + this._closeTreeBtn.Height = 25; + this._closeTreeBtn.Width = 100; + this._remoteDirectoryTreeView = new TreeView(); + this._remoteDirectoryTreeView.ImageList = _imgList; + this._remoteDirectoryTreeView.ContextMenuStrip = this.treeContext; + this._remoteDirectoryTreeView.DoubleClick += remoteDirectoryTreeView_DoubleClick; + this._remoteDirectoryTreeView.Hide(); + this.Controls.Add(_remoteDirectoryTreeView); + this.Controls.Add(_closeTreeBtn); + IntPtr sysMenuHandle = GetSystemMenu(this.Handle, false); int index = 7; diff --git a/SiMay.RemoteMonitor/Application/ScreenApplication.cs b/SiMay.RemoteMonitor/Application/ScreenApplication.cs index 9c532af..77e409c 100644 --- a/SiMay.RemoteMonitor/Application/ScreenApplication.cs +++ b/SiMay.RemoteMonitor/Application/ScreenApplication.cs @@ -13,7 +13,7 @@ using SiMay.RemoteMonitor.MainApplication; using SiMay.Net.SessionProvider.SessionBased; using SiMay.RemoteControlsCore.HandlerAdapters; using static SiMay.RemoteMonitor.Win32Api; -using static SiMay.Serialize.PacketSerializeHelper; +using static SiMay.Serialize.Standard.PacketSerializeHelper; namespace SiMay.RemoteMonitor.Application { diff --git a/SiMay.RemoteMonitor/Helper/ListViewSortHelper.cs b/SiMay.RemoteMonitor/Helper/ListViewSortHelper.cs index 2435fc8..c9af699 100644 --- a/SiMay.RemoteMonitor/Helper/ListViewSortHelper.cs +++ b/SiMay.RemoteMonitor/Helper/ListViewSortHelper.cs @@ -4,7 +4,7 @@ using System.Linq; using System.Text; using System.Threading.Tasks; -namespace SiMay.RemoteMonitor.Entitys +namespace SiMay.RemoteMonitor { /// /// 继承自IComparer diff --git a/SiMay.Basic/MessageBoxHelper.cs b/SiMay.RemoteMonitor/Helper/MessageBoxHelper.cs similarity index 95% rename from SiMay.Basic/MessageBoxHelper.cs rename to SiMay.RemoteMonitor/Helper/MessageBoxHelper.cs index 3868ea7..d4bf4ee 100644 --- a/SiMay.Basic/MessageBoxHelper.cs +++ b/SiMay.RemoteMonitor/Helper/MessageBoxHelper.cs @@ -4,7 +4,7 @@ using System.Linq; using System.Text; using System.Windows.Forms; -namespace SiMay.Basic +namespace SiMay.RemoteMonitor { public class MessageBoxHelper { diff --git a/SiMay.RemoteMonitor/MainApplication/BuilderServiceForm.cs b/SiMay.RemoteMonitor/MainApplication/BuilderServiceForm.cs index 2c0ae18..a2c9e20 100644 --- a/SiMay.RemoteMonitor/MainApplication/BuilderServiceForm.cs +++ b/SiMay.RemoteMonitor/MainApplication/BuilderServiceForm.cs @@ -1,8 +1,7 @@ using SiMay.Basic; using SiMay.Core.Entitys; using SiMay.RemoteControlsCore; -using SiMay.RemoteMonitor.Entitys; -using SiMay.Serialize; +using SiMay.Serialize.Standard; using System; using System.Collections.Generic; using System.IO; diff --git a/SiMay.RemoteMonitor/MainApplication/DesktopRecordForm.cs b/SiMay.RemoteMonitor/MainApplication/DesktopRecordForm.cs index 5a8c2f6..2a18bae 100644 --- a/SiMay.RemoteMonitor/MainApplication/DesktopRecordForm.cs +++ b/SiMay.RemoteMonitor/MainApplication/DesktopRecordForm.cs @@ -23,7 +23,7 @@ namespace SiMay.RemoteMonitor.MainApplication private void DesktopRecordManager_Load(object sender, EventArgs e) { - bool isAction = _syncContext.KeyDictions[SysConstants.RecordScreenIsAction].ConvertTo(); + bool isAction = _syncContext.KeyDictions[SysConstants.HasLaunchDesktopRecord].ConvertTo(); string macName = _syncContext.KeyDictions[SysConstants.MachineName].ConvertTo(); int screenHeight = _syncContext.KeyDictions[SysConstants.RecordHeight].ConvertTo(); int screenWidth = _syncContext.KeyDictions[SysConstants.RecordWidth].ConvertTo(); @@ -68,7 +68,7 @@ namespace SiMay.RemoteMonitor.MainApplication //_session.SendAsync(data); - _syncContext.KeyDictions[SysConstants.RecordScreenIsAction] = true; + _syncContext.KeyDictions[SysConstants.HasLaunchDesktopRecord] = true; _syncContext.KeyDictions[SysConstants.RecordHeight] = screenHeight; _syncContext.KeyDictions[SysConstants.RecordWidth] = screenWidth; _syncContext.KeyDictions[SysConstants.RecordSpanTime] = spantime; @@ -82,7 +82,7 @@ namespace SiMay.RemoteMonitor.MainApplication //byte[] data = MessageHelper.CopyMessageHeadTo(MessageHead.S_MAIN_SCREEN_RECORD_CLOSE); //_session.SendAsync(data); - _syncContext.KeyDictions[SysConstants.RecordScreenIsAction] = false; + _syncContext.KeyDictions[SysConstants.HasLaunchDesktopRecord] = false; startbtn.Enabled = true; stopbtn.Enabled = false; } diff --git a/SiMay.RemoteMonitor/SiMay.RemoteMonitor.csproj b/SiMay.RemoteMonitor/SiMay.RemoteMonitor.csproj index 524b710..79ebaa4 100644 --- a/SiMay.RemoteMonitor/SiMay.RemoteMonitor.csproj +++ b/SiMay.RemoteMonitor/SiMay.RemoteMonitor.csproj @@ -158,6 +158,7 @@ + Form @@ -497,7 +498,7 @@ - {b30cd716-698a-4da2-bd1a-c152b16993c0} + {8f2f35cb-d5ee-4d92-b42f-bcffbf9c9d4f} SiMay.Basic @@ -505,16 +506,16 @@ SiMay.Core - {BF5B6F41-D688-447F-BF81-EA821216F188} + {71283236-56cb-481e-a644-b7f9af9efdf9} SiMay.Net.SessionProvider {44dfa13c-03c3-4f07-9d78-30f981bfabc5} SiMay.RemoteControlsCore - - {4888d6bb-46d9-4519-8758-e13e397aa226} - SiMay.Serialize + + {9525a4aa-6731-4ab2-8cd0-addf7940fe32} + SiMay.Serialize.Standard diff --git a/SiMay.Serialize/PacketDeserializeSetup.cs b/SiMay.Serialize.Standard/PacketDeserializeSetup.cs similarity index 99% rename from SiMay.Serialize/PacketDeserializeSetup.cs rename to SiMay.Serialize.Standard/PacketDeserializeSetup.cs index c248f6c..8ce6674 100644 --- a/SiMay.Serialize/PacketDeserializeSetup.cs +++ b/SiMay.Serialize.Standard/PacketDeserializeSetup.cs @@ -6,7 +6,7 @@ using System.Linq; using System.Reflection; using System.Text; -namespace SiMay.Serialize +namespace SiMay.Serialize.Standard { public class PacketDeserializeSetup { diff --git a/SiMay.Serialize/PacketSerializeHelper.cs b/SiMay.Serialize.Standard/PacketSerializeHelper.cs similarity index 94% rename from SiMay.Serialize/PacketSerializeHelper.cs rename to SiMay.Serialize.Standard/PacketSerializeHelper.cs index 66c94c0..fbe9eea 100644 --- a/SiMay.Serialize/PacketSerializeHelper.cs +++ b/SiMay.Serialize.Standard/PacketSerializeHelper.cs @@ -4,7 +4,7 @@ using System.Collections.Generic; using System.Linq; using System.Text; -namespace SiMay.Serialize +namespace SiMay.Serialize.Standard { public class PacketSerializeHelper { diff --git a/SiMay.Serialize/PacketSerializeSetup.cs b/SiMay.Serialize.Standard/PacketSerializeSetup.cs similarity index 99% rename from SiMay.Serialize/PacketSerializeSetup.cs rename to SiMay.Serialize.Standard/PacketSerializeSetup.cs index 995a010..4075471 100644 --- a/SiMay.Serialize/PacketSerializeSetup.cs +++ b/SiMay.Serialize.Standard/PacketSerializeSetup.cs @@ -6,7 +6,7 @@ using System.IO; using System.Linq; using System.Text; -namespace SiMay.Serialize +namespace SiMay.Serialize.Standard { public class PacketSerializeSetup { diff --git a/SiMay.Serialize/ReflectCachePool/DynamicMethodMemberAccessor.cs b/SiMay.Serialize.Standard/ReflectCachePool/DynamicMethodMemberAccessor.cs similarity index 100% rename from SiMay.Serialize/ReflectCachePool/DynamicMethodMemberAccessor.cs rename to SiMay.Serialize.Standard/ReflectCachePool/DynamicMethodMemberAccessor.cs diff --git a/SiMay.Serialize/ReflectCachePool/EntitySerializerBase.cs b/SiMay.Serialize.Standard/ReflectCachePool/EntitySerializerBase.cs similarity index 100% rename from SiMay.Serialize/ReflectCachePool/EntitySerializerBase.cs rename to SiMay.Serialize.Standard/ReflectCachePool/EntitySerializerBase.cs diff --git a/SiMay.Serialize/ReflectCachePool/IMemberAccessor.cs b/SiMay.Serialize.Standard/ReflectCachePool/IMemberAccessor.cs similarity index 100% rename from SiMay.Serialize/ReflectCachePool/IMemberAccessor.cs rename to SiMay.Serialize.Standard/ReflectCachePool/IMemberAccessor.cs diff --git a/SiMay.Serialize.Standard/SiMay.Serialize.Standard.csproj b/SiMay.Serialize.Standard/SiMay.Serialize.Standard.csproj new file mode 100644 index 0000000..9f5c4f4 --- /dev/null +++ b/SiMay.Serialize.Standard/SiMay.Serialize.Standard.csproj @@ -0,0 +1,7 @@ + + + + netstandard2.0 + + + diff --git a/SiMay.Serialize/Properties/AssemblyInfo.cs b/SiMay.Serialize/Properties/AssemblyInfo.cs deleted file mode 100644 index 35498b4..0000000 --- a/SiMay.Serialize/Properties/AssemblyInfo.cs +++ /dev/null @@ -1,36 +0,0 @@ -using System.Reflection; -using System.Runtime.CompilerServices; -using System.Runtime.InteropServices; - -// 有关程序集的一般信息由以下 -// 控制。更改这些特性值可修改 -// 与程序集关联的信息。 -[assembly: AssemblyTitle("SiMay.Serialize")] -[assembly: AssemblyDescription("")] -[assembly: AssemblyConfiguration("")] -[assembly: AssemblyCompany("Microsoft")] -[assembly: AssemblyProduct("SiMay.Serialize")] -[assembly: AssemblyCopyright("Copyright © Microsoft 2019")] -[assembly: AssemblyTrademark("")] -[assembly: AssemblyCulture("")] - -// 将 ComVisible 设置为 false 会使此程序集中的类型 -//对 COM 组件不可见。如果需要从 COM 访问此程序集中的类型 -//请将此类型的 ComVisible 特性设置为 true。 -[assembly: ComVisible(false)] - -// 如果此项目向 COM 公开,则下列 GUID 用于类型库的 ID -[assembly: Guid("4888d6bb-46d9-4519-8758-e13e397aa226")] - -// 程序集的版本信息由下列四个值组成: -// -// 主版本 -// 次版本 -// 生成号 -// 修订号 -// -//可以指定所有这些值,也可以使用“生成号”和“修订号”的默认值 -//通过使用 "*",如下所示: -// [assembly: AssemblyVersion("1.0.*")] -[assembly: AssemblyVersion("1.0.0.0")] -[assembly: AssemblyFileVersion("1.0.0.0")] diff --git a/SiMay.Serialize/README.md b/SiMay.Serialize/README.md deleted file mode 100644 index e69de29..0000000 diff --git a/SiMay.Serialize/SiMaySerialize.sln b/SiMay.Serialize/SiMaySerialize.sln deleted file mode 100644 index 3370f66..0000000 --- a/SiMay.Serialize/SiMaySerialize.sln +++ /dev/null @@ -1,37 +0,0 @@ - -Microsoft Visual Studio Solution File, Format Version 12.00 -# Visual Studio Version 16 -VisualStudioVersion = 16.0.28803.352 -MinimumVisualStudioVersion = 10.0.40219.1 -Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "SiMay.Serialize", "SiMay.Serialize.csproj", "{4888D6BB-46D9-4519-8758-E13E397AA226}" -EndProject -Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "SiMaySerializeTestApp", "SiMaySerializeTestApp\SiMaySerializeTestApp.csproj", "{84A4241A-3773-4B84-868F-9573FFF7F161}" -EndProject -Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "SiMaySerializeTestApp2", "..\SiMaySerializeTestApp2\SiMaySerializeTestApp2.csproj", "{263A26F1-5235-4EA5-B2D6-ADF219A07CD2}" -EndProject -Global - GlobalSection(SolutionConfigurationPlatforms) = preSolution - Debug|Any CPU = Debug|Any CPU - Release|Any CPU = Release|Any CPU - EndGlobalSection - GlobalSection(ProjectConfigurationPlatforms) = postSolution - {4888D6BB-46D9-4519-8758-E13E397AA226}.Debug|Any CPU.ActiveCfg = Debug|Any CPU - {4888D6BB-46D9-4519-8758-E13E397AA226}.Debug|Any CPU.Build.0 = Debug|Any CPU - {4888D6BB-46D9-4519-8758-E13E397AA226}.Release|Any CPU.ActiveCfg = Release|Any CPU - {4888D6BB-46D9-4519-8758-E13E397AA226}.Release|Any CPU.Build.0 = Release|Any CPU - {84A4241A-3773-4B84-868F-9573FFF7F161}.Debug|Any CPU.ActiveCfg = Debug|Any CPU - {84A4241A-3773-4B84-868F-9573FFF7F161}.Debug|Any CPU.Build.0 = Debug|Any CPU - {84A4241A-3773-4B84-868F-9573FFF7F161}.Release|Any CPU.ActiveCfg = Release|Any CPU - {84A4241A-3773-4B84-868F-9573FFF7F161}.Release|Any CPU.Build.0 = Release|Any CPU - {263A26F1-5235-4EA5-B2D6-ADF219A07CD2}.Debug|Any CPU.ActiveCfg = Debug|Any CPU - {263A26F1-5235-4EA5-B2D6-ADF219A07CD2}.Debug|Any CPU.Build.0 = Debug|Any CPU - {263A26F1-5235-4EA5-B2D6-ADF219A07CD2}.Release|Any CPU.ActiveCfg = Release|Any CPU - {263A26F1-5235-4EA5-B2D6-ADF219A07CD2}.Release|Any CPU.Build.0 = Release|Any CPU - EndGlobalSection - GlobalSection(SolutionProperties) = preSolution - HideSolutionNode = FALSE - EndGlobalSection - GlobalSection(ExtensibilityGlobals) = postSolution - SolutionGuid = {AE976174-2305-42E9-8445-EEC36625B83E} - EndGlobalSection -EndGlobal diff --git a/SiMay.Serialize/SiMaySerializeTestApp/Program.cs b/SiMay.Serialize/SiMaySerializeTestApp/Program.cs deleted file mode 100644 index e246ea3..0000000 --- a/SiMay.Serialize/SiMaySerializeTestApp/Program.cs +++ /dev/null @@ -1,85 +0,0 @@ -using SiMay.ReflectCache; -using SiMay.Serialize; -using System; -using System.Collections.Generic; -using System.Diagnostics; -using System.Linq; -using System.Text; - -namespace SiMaySerializeTestApp -{ - class Program - { - public class TestB : PacketBase - { - public bool[] isArray { get; set; } - public bool isSuccess { get; set; } - public byte[] Data { get; set; } - public int Id { get; set; } - } - public class TestA : PacketBase - { - public int Id { get; set; } - public int[] Ids { get; set; } - public string Name { get; set; } - public string[] Names { get; set; } - public TestB B { get; set; } - public TestA[] As { get; set; } - public DateTime Time { get; set; } - public MyEnum MyEnum { get; set; } - public double[] bs { get; set; } = new double[] { 123, 132 }; - } - public enum MyEnum - { - A, B, C - } - static void Main(string[] args) - { - DynamicMethodMemberAccessor.FindClassAccessor(typeof(TestA)); - List list = new List(); - for (int i = 0; i < 5; i++) - { - TestA a = new TestA() - { - Id = 12313213 + i, - Ids = new int[] { 1213, 11, 1 }, - Name = "哈哈哈", - Names = new string[] { "嘿嘿", "AAA" }, - B = new TestB() - { - isSuccess = true, - Id = 12132132 + i, - Data = new byte[] { 1, 2, 255 } - }, - As = new TestA[] { }, - Time = DateTime.Now - }; - list.Add(a); - } - TestA A = new TestA() - { - Id = 123, - Ids = null, - Name = null, - Names = null, - B = null, - As = list.ToArray(), - //Time = DateTime.Now, - MyEnum = MyEnum.B - }; - - Stopwatch sw = new Stopwatch(); - sw.Start(); - var bytes = PacketSerializeHelper.SerializePacket(A); - sw.Stop(); - Console.WriteLine("序列化耗时:" + sw.Elapsed.TotalSeconds); - sw.Reset(); - sw.Start(); - TestA pack = PacketSerializeHelper.DeserializePacket(bytes); - sw.Stop(); - Console.WriteLine("反序列化耗时:" + sw.Elapsed.TotalSeconds); - - Console.Read(); - } - } -} diff --git a/SiMay.Serialize/SiMaySerializeTestApp/Properties/AssemblyInfo.cs b/SiMay.Serialize/SiMaySerializeTestApp/Properties/AssemblyInfo.cs deleted file mode 100644 index 61059ab..0000000 --- a/SiMay.Serialize/SiMaySerializeTestApp/Properties/AssemblyInfo.cs +++ /dev/null @@ -1,36 +0,0 @@ -using System.Reflection; -using System.Runtime.CompilerServices; -using System.Runtime.InteropServices; - -// 有关程序集的一般信息由以下 -// 控制。更改这些特性值可修改 -// 与程序集关联的信息。 -[assembly: AssemblyTitle("SiMaySerializeTestApp")] -[assembly: AssemblyDescription("")] -[assembly: AssemblyConfiguration("")] -[assembly: AssemblyCompany("")] -[assembly: AssemblyProduct("SiMaySerializeTestApp")] -[assembly: AssemblyCopyright("Copyright © 2019")] -[assembly: AssemblyTrademark("")] -[assembly: AssemblyCulture("")] - -// 将 ComVisible 设置为 false 会使此程序集中的类型 -//对 COM 组件不可见。如果需要从 COM 访问此程序集中的类型 -//请将此类型的 ComVisible 特性设置为 true。 -[assembly: ComVisible(false)] - -// 如果此项目向 COM 公开,则下列 GUID 用于类型库的 ID -[assembly: Guid("84a4241a-3773-4b84-868f-9573fff7f161")] - -// 程序集的版本信息由下列四个值组成: -// -// 主版本 -// 次版本 -// 生成号 -// 修订号 -// -//可以指定所有这些值,也可以使用“生成号”和“修订号”的默认值 -//通过使用 "*",如下所示: -// [assembly: AssemblyVersion("1.0.*")] -[assembly: AssemblyVersion("1.0.0.0")] -[assembly: AssemblyFileVersion("1.0.0.0")] diff --git a/SiMay.Serialize/SiMaySerializeTestApp/SiMaySerializeTestApp.csproj b/SiMay.Serialize/SiMaySerializeTestApp/SiMaySerializeTestApp.csproj deleted file mode 100644 index 4f425a8..0000000 --- a/SiMay.Serialize/SiMaySerializeTestApp/SiMaySerializeTestApp.csproj +++ /dev/null @@ -1,54 +0,0 @@ - - - - - Debug - AnyCPU - {84A4241A-3773-4B84-868F-9573FFF7F161} - Exe - SiMaySerializeTestApp - SiMaySerializeTestApp - v4.0 - 512 - true - - - AnyCPU - true - full - false - bin\Debug\ - DEBUG;TRACE - prompt - 4 - - - AnyCPU - pdbonly - true - bin\Release\ - TRACE - prompt - 4 - - - - - - - - - - - - - - - - - {4888D6BB-46D9-4519-8758-E13E397AA226} - SiMay.Serialize - - - - \ No newline at end of file diff --git a/SiMay.Sockets.Standard/SiMay.Sockets.Standard.csproj b/SiMay.Sockets.Standard/SiMay.Sockets.Standard.csproj index 77ac0c3..7fad7cd 100644 --- a/SiMay.Sockets.Standard/SiMay.Sockets.Standard.csproj +++ b/SiMay.Sockets.Standard/SiMay.Sockets.Standard.csproj @@ -4,6 +4,10 @@ netstandard2.0 + + E:\MyFiles\Desktop\SiMayRemoteMonitorOS\Bin\ + + C:\Program Files (x86)\Reference Assemblies\Microsoft\Framework\.NETFramework\v4.6.1\System.dll diff --git a/SiMay.Sockets.Standard/Tcp/Session/TcpSocketSaeaPackBased.cs b/SiMay.Sockets.Standard/Tcp/Session/TcpSocketSaeaPackBased.cs index 5f9fe0d..087949d 100644 --- a/SiMay.Sockets.Standard/Tcp/Session/TcpSocketSaeaPackBased.cs +++ b/SiMay.Sockets.Standard/Tcp/Session/TcpSocketSaeaPackBased.cs @@ -185,7 +185,7 @@ namespace SiMay.Sockets.Tcp.Session private void PackageProcess() { if (this._isCompress) - CompletedBuffer = DeCompressHelper.GzipDecompress(CompletedBuffer); + CompletedBuffer = GZipHelper.Decompress(CompletedBuffer); this.NotifyEventHandler?.Invoke(TcpSocketCompletionNotify.OnDataReceived, this); } @@ -205,7 +205,7 @@ namespace SiMay.Sockets.Tcp.Session return; byte[] buffer = this._isCompress - ? this.BuilderPack(DeCompressHelper.GZipCompress(data, offset, lenght)) + ? this.BuilderPack(GZipHelper.Compress(data, offset, lenght)) : this.BuilderPack(data, offset, lenght); var awaiter = HandlerSaeaPool.Take(); diff --git a/SiMay.Sockets.Standard/Tcp/Session/TcpSocketSaeaSession.cs b/SiMay.Sockets.Standard/Tcp/Session/TcpSocketSaeaSession.cs index bf2f494..4781040 100644 --- a/SiMay.Sockets.Standard/Tcp/Session/TcpSocketSaeaSession.cs +++ b/SiMay.Sockets.Standard/Tcp/Session/TcpSocketSaeaSession.cs @@ -10,6 +10,9 @@ using System.Text; namespace SiMay.Sockets.Tcp.Session { + /// + /// 提供不同数据接收处理方式的抽象类(PACK和FULL) + /// public abstract class TcpSocketSaeaSession { protected NotifyEventHandler NotifyEventHandler { get; set; } diff --git a/SiMay.Sockets.Standard/UtilityHelper/DeCompressHelper.cs b/SiMay.Sockets.Standard/UtilityHelper/GZipHelper.cs similarity index 90% rename from SiMay.Sockets.Standard/UtilityHelper/DeCompressHelper.cs rename to SiMay.Sockets.Standard/UtilityHelper/GZipHelper.cs index 207d218..f91068a 100644 --- a/SiMay.Sockets.Standard/UtilityHelper/DeCompressHelper.cs +++ b/SiMay.Sockets.Standard/UtilityHelper/GZipHelper.cs @@ -7,9 +7,9 @@ using System.Text; namespace SiMay.Sockets.UtilityHelper { - class DeCompressHelper + class GZipHelper { - public static byte[] GZipCompress(byte[] data, int offset, int lenght) + public static byte[] Compress(byte[] data, int offset, int lenght) { byte[] buffer = null; try @@ -27,7 +27,7 @@ namespace SiMay.Sockets.UtilityHelper return buffer; } - public static byte[] GzipDecompress(byte[] data) + public static byte[] Decompress(byte[] data) { byte[] buffer = null; try diff --git a/SiMayRemoteManager.sln b/SiMayRemoteMonitorOS.sln similarity index 68% rename from SiMayRemoteManager.sln rename to SiMayRemoteMonitorOS.sln index add4b0d..154c3e7 100644 --- a/SiMayRemoteManager.sln +++ b/SiMayRemoteMonitorOS.sln @@ -9,14 +9,8 @@ Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "SiMay.Core", "SiMay.Core\Si EndProject Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "SiMay.ServiceCore", "SiMay.RemoteClient.NewCore\SiMay.ServiceCore.csproj", "{8D061D46-9E59-42B0-91DC-4E380E4AE0BA}" EndProject -Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "SiMay.Net.SessionProvider", "SiMay.Net.SessionProvider\SiMay.Net.SessionProvider.csproj", "{BF5B6F41-D688-447F-BF81-EA821216F188}" -EndProject Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "SiMay.Net.SessionProviderService", "SiMay.Net.SessionProviderService\SiMay.Net.SessionProviderService.csproj", "{61FB6C20-4541-40D1-AC4B-3ECDACF5F633}" EndProject -Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "SiMay.Net.SessionProvider.Core", "SiMay.Net.SessionProvider.Core\SiMay.Net.SessionProvider.Core.csproj", "{8BFDB408-D26D-4689-B426-BE45AD195880}" -EndProject -Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "SiMay.Basic", "SiMay.Basic\SiMay.Basic.csproj", "{B30CD716-698A-4DA2-BD1A-C152B16993C0}" -EndProject Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "SiMay.RemoteService", "SiMay.RemoteService", "{FBA5D1FE-11EA-4FAE-B88F-7E2E809419C9}" EndProject Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "SiMay.RemoteMonitor", "SiMay.RemoteMonitor", "{A86A6BBD-1122-4993-B472-6A0265E5F2A1}" @@ -27,14 +21,22 @@ Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "SiMay.Sockets", "SiMay.Sock EndProject Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "SiMay.SessionProvider", "SiMay.SessionProvider", "{9328FEED-6E95-4863-BB7B-521D0D02D7FA}" EndProject -Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "SiMay.Serialize", "SiMay.Serialize\SiMay.Serialize.csproj", "{4888D6BB-46D9-4519-8758-E13E397AA226}" -EndProject Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "SiMay.RemoteControlsCore", "SiMay.RemoteControlsCore\SiMay.RemoteControlsCore.csproj", "{44DFA13C-03C3-4F07-9D78-30F981BFABC5}" EndProject Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "SiMay.Sockets.Standard", "SiMay.Sockets.Standard\SiMay.Sockets.Standard.csproj", "{866F8FE0-EE58-4D38-8BE7-CBDD19DD1B40}" EndProject Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "SiMay.RemoteService.Loader", "SiMay.RemoteService.Loader\SiMay.RemoteService.Loader.csproj", "{7EFE8058-F772-40EB-8E12-6E88E2A9E19A}" EndProject +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "SiMay.Net.SessionProviderServiceCore", "SiMay.Net.SessionProviderServiceCore\SiMay.Net.SessionProviderServiceCore.csproj", "{3C91F949-5187-4CDF-9A5B-AA3C20F7544B}" +EndProject +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "SiMay.Basic", "SiMay.Basic\SiMay.Basic.csproj", "{8F2F35CB-D5EE-4D92-B42F-BCFFBF9C9D4F}" +EndProject +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "SiMay.Serialize.Standard", "SiMay.Serialize.Standard\SiMay.Serialize.Standard.csproj", "{9525A4AA-6731-4AB2-8CD0-ADDF7940FE32}" +EndProject +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "SiMay.Net.SessionProvider", "SiMay.Net.SessionProvider\SiMay.Net.SessionProvider.csproj", "{71283236-56CB-481E-A644-B7F9AF9EFDF9}" +EndProject +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "SiMay.Net.SessionProvider.Core", "SiMay.Net.SessionProvider.Core\SiMay.Net.SessionProvider.Core.csproj", "{0B2B697D-DD20-4869-836C-08C848E1813F}" +EndProject Global GlobalSection(SolutionConfigurationPlatforms) = preSolution Debug|Any CPU = Debug|Any CPU @@ -82,18 +84,6 @@ Global {8D061D46-9E59-42B0-91DC-4E380E4AE0BA}.Release|x64.Build.0 = Release|x64 {8D061D46-9E59-42B0-91DC-4E380E4AE0BA}.Release|x86.ActiveCfg = Release|Any CPU {8D061D46-9E59-42B0-91DC-4E380E4AE0BA}.Release|x86.Build.0 = Release|Any CPU - {BF5B6F41-D688-447F-BF81-EA821216F188}.Debug|Any CPU.ActiveCfg = Debug|Any CPU - {BF5B6F41-D688-447F-BF81-EA821216F188}.Debug|Any CPU.Build.0 = Debug|Any CPU - {BF5B6F41-D688-447F-BF81-EA821216F188}.Debug|x64.ActiveCfg = Debug|Any CPU - {BF5B6F41-D688-447F-BF81-EA821216F188}.Debug|x64.Build.0 = Debug|Any CPU - {BF5B6F41-D688-447F-BF81-EA821216F188}.Debug|x86.ActiveCfg = Debug|Any CPU - {BF5B6F41-D688-447F-BF81-EA821216F188}.Debug|x86.Build.0 = Debug|Any CPU - {BF5B6F41-D688-447F-BF81-EA821216F188}.Release|Any CPU.ActiveCfg = Release|Any CPU - {BF5B6F41-D688-447F-BF81-EA821216F188}.Release|Any CPU.Build.0 = Release|Any CPU - {BF5B6F41-D688-447F-BF81-EA821216F188}.Release|x64.ActiveCfg = Release|Any CPU - {BF5B6F41-D688-447F-BF81-EA821216F188}.Release|x64.Build.0 = Release|Any CPU - {BF5B6F41-D688-447F-BF81-EA821216F188}.Release|x86.ActiveCfg = Release|Any CPU - {BF5B6F41-D688-447F-BF81-EA821216F188}.Release|x86.Build.0 = Release|Any CPU {61FB6C20-4541-40D1-AC4B-3ECDACF5F633}.Debug|Any CPU.ActiveCfg = Debug|Any CPU {61FB6C20-4541-40D1-AC4B-3ECDACF5F633}.Debug|Any CPU.Build.0 = Debug|Any CPU {61FB6C20-4541-40D1-AC4B-3ECDACF5F633}.Debug|x64.ActiveCfg = Debug|Any CPU @@ -106,42 +96,6 @@ Global {61FB6C20-4541-40D1-AC4B-3ECDACF5F633}.Release|x64.Build.0 = Release|Any CPU {61FB6C20-4541-40D1-AC4B-3ECDACF5F633}.Release|x86.ActiveCfg = Release|Any CPU {61FB6C20-4541-40D1-AC4B-3ECDACF5F633}.Release|x86.Build.0 = Release|Any CPU - {8BFDB408-D26D-4689-B426-BE45AD195880}.Debug|Any CPU.ActiveCfg = Debug|Any CPU - {8BFDB408-D26D-4689-B426-BE45AD195880}.Debug|Any CPU.Build.0 = Debug|Any CPU - {8BFDB408-D26D-4689-B426-BE45AD195880}.Debug|x64.ActiveCfg = Debug|Any CPU - {8BFDB408-D26D-4689-B426-BE45AD195880}.Debug|x64.Build.0 = Debug|Any CPU - {8BFDB408-D26D-4689-B426-BE45AD195880}.Debug|x86.ActiveCfg = Debug|Any CPU - {8BFDB408-D26D-4689-B426-BE45AD195880}.Debug|x86.Build.0 = Debug|Any CPU - {8BFDB408-D26D-4689-B426-BE45AD195880}.Release|Any CPU.ActiveCfg = Release|Any CPU - {8BFDB408-D26D-4689-B426-BE45AD195880}.Release|Any CPU.Build.0 = Release|Any CPU - {8BFDB408-D26D-4689-B426-BE45AD195880}.Release|x64.ActiveCfg = Release|Any CPU - {8BFDB408-D26D-4689-B426-BE45AD195880}.Release|x64.Build.0 = Release|Any CPU - {8BFDB408-D26D-4689-B426-BE45AD195880}.Release|x86.ActiveCfg = Release|Any CPU - {8BFDB408-D26D-4689-B426-BE45AD195880}.Release|x86.Build.0 = Release|Any CPU - {B30CD716-698A-4DA2-BD1A-C152B16993C0}.Debug|Any CPU.ActiveCfg = Debug|Any CPU - {B30CD716-698A-4DA2-BD1A-C152B16993C0}.Debug|Any CPU.Build.0 = Debug|Any CPU - {B30CD716-698A-4DA2-BD1A-C152B16993C0}.Debug|x64.ActiveCfg = Debug|Any CPU - {B30CD716-698A-4DA2-BD1A-C152B16993C0}.Debug|x64.Build.0 = Debug|Any CPU - {B30CD716-698A-4DA2-BD1A-C152B16993C0}.Debug|x86.ActiveCfg = Debug|Any CPU - {B30CD716-698A-4DA2-BD1A-C152B16993C0}.Debug|x86.Build.0 = Debug|Any CPU - {B30CD716-698A-4DA2-BD1A-C152B16993C0}.Release|Any CPU.ActiveCfg = Release|Any CPU - {B30CD716-698A-4DA2-BD1A-C152B16993C0}.Release|Any CPU.Build.0 = Release|Any CPU - {B30CD716-698A-4DA2-BD1A-C152B16993C0}.Release|x64.ActiveCfg = Release|Any CPU - {B30CD716-698A-4DA2-BD1A-C152B16993C0}.Release|x64.Build.0 = Release|Any CPU - {B30CD716-698A-4DA2-BD1A-C152B16993C0}.Release|x86.ActiveCfg = Release|Any CPU - {B30CD716-698A-4DA2-BD1A-C152B16993C0}.Release|x86.Build.0 = Release|Any CPU - {4888D6BB-46D9-4519-8758-E13E397AA226}.Debug|Any CPU.ActiveCfg = Debug|Any CPU - {4888D6BB-46D9-4519-8758-E13E397AA226}.Debug|Any CPU.Build.0 = Debug|Any CPU - {4888D6BB-46D9-4519-8758-E13E397AA226}.Debug|x64.ActiveCfg = Debug|Any CPU - {4888D6BB-46D9-4519-8758-E13E397AA226}.Debug|x64.Build.0 = Debug|Any CPU - {4888D6BB-46D9-4519-8758-E13E397AA226}.Debug|x86.ActiveCfg = Debug|Any CPU - {4888D6BB-46D9-4519-8758-E13E397AA226}.Debug|x86.Build.0 = Debug|Any CPU - {4888D6BB-46D9-4519-8758-E13E397AA226}.Release|Any CPU.ActiveCfg = Release|Any CPU - {4888D6BB-46D9-4519-8758-E13E397AA226}.Release|Any CPU.Build.0 = Release|Any CPU - {4888D6BB-46D9-4519-8758-E13E397AA226}.Release|x64.ActiveCfg = Release|Any CPU - {4888D6BB-46D9-4519-8758-E13E397AA226}.Release|x64.Build.0 = Release|Any CPU - {4888D6BB-46D9-4519-8758-E13E397AA226}.Release|x86.ActiveCfg = Release|Any CPU - {4888D6BB-46D9-4519-8758-E13E397AA226}.Release|x86.Build.0 = Release|Any CPU {44DFA13C-03C3-4F07-9D78-30F981BFABC5}.Debug|Any CPU.ActiveCfg = Debug|Any CPU {44DFA13C-03C3-4F07-9D78-30F981BFABC5}.Debug|Any CPU.Build.0 = Debug|Any CPU {44DFA13C-03C3-4F07-9D78-30F981BFABC5}.Debug|x64.ActiveCfg = Debug|Any CPU @@ -178,6 +132,66 @@ Global {7EFE8058-F772-40EB-8E12-6E88E2A9E19A}.Release|x64.Build.0 = Release|Any CPU {7EFE8058-F772-40EB-8E12-6E88E2A9E19A}.Release|x86.ActiveCfg = Release|Any CPU {7EFE8058-F772-40EB-8E12-6E88E2A9E19A}.Release|x86.Build.0 = Release|Any CPU + {3C91F949-5187-4CDF-9A5B-AA3C20F7544B}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {3C91F949-5187-4CDF-9A5B-AA3C20F7544B}.Debug|Any CPU.Build.0 = Debug|Any CPU + {3C91F949-5187-4CDF-9A5B-AA3C20F7544B}.Debug|x64.ActiveCfg = Debug|Any CPU + {3C91F949-5187-4CDF-9A5B-AA3C20F7544B}.Debug|x64.Build.0 = Debug|Any CPU + {3C91F949-5187-4CDF-9A5B-AA3C20F7544B}.Debug|x86.ActiveCfg = Debug|Any CPU + {3C91F949-5187-4CDF-9A5B-AA3C20F7544B}.Debug|x86.Build.0 = Debug|Any CPU + {3C91F949-5187-4CDF-9A5B-AA3C20F7544B}.Release|Any CPU.ActiveCfg = Release|Any CPU + {3C91F949-5187-4CDF-9A5B-AA3C20F7544B}.Release|Any CPU.Build.0 = Release|Any CPU + {3C91F949-5187-4CDF-9A5B-AA3C20F7544B}.Release|x64.ActiveCfg = Release|Any CPU + {3C91F949-5187-4CDF-9A5B-AA3C20F7544B}.Release|x64.Build.0 = Release|Any CPU + {3C91F949-5187-4CDF-9A5B-AA3C20F7544B}.Release|x86.ActiveCfg = Release|Any CPU + {3C91F949-5187-4CDF-9A5B-AA3C20F7544B}.Release|x86.Build.0 = Release|Any CPU + {8F2F35CB-D5EE-4D92-B42F-BCFFBF9C9D4F}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {8F2F35CB-D5EE-4D92-B42F-BCFFBF9C9D4F}.Debug|Any CPU.Build.0 = Debug|Any CPU + {8F2F35CB-D5EE-4D92-B42F-BCFFBF9C9D4F}.Debug|x64.ActiveCfg = Debug|Any CPU + {8F2F35CB-D5EE-4D92-B42F-BCFFBF9C9D4F}.Debug|x64.Build.0 = Debug|Any CPU + {8F2F35CB-D5EE-4D92-B42F-BCFFBF9C9D4F}.Debug|x86.ActiveCfg = Debug|Any CPU + {8F2F35CB-D5EE-4D92-B42F-BCFFBF9C9D4F}.Debug|x86.Build.0 = Debug|Any CPU + {8F2F35CB-D5EE-4D92-B42F-BCFFBF9C9D4F}.Release|Any CPU.ActiveCfg = Release|Any CPU + {8F2F35CB-D5EE-4D92-B42F-BCFFBF9C9D4F}.Release|Any CPU.Build.0 = Release|Any CPU + {8F2F35CB-D5EE-4D92-B42F-BCFFBF9C9D4F}.Release|x64.ActiveCfg = Release|Any CPU + {8F2F35CB-D5EE-4D92-B42F-BCFFBF9C9D4F}.Release|x64.Build.0 = Release|Any CPU + {8F2F35CB-D5EE-4D92-B42F-BCFFBF9C9D4F}.Release|x86.ActiveCfg = Release|Any CPU + {8F2F35CB-D5EE-4D92-B42F-BCFFBF9C9D4F}.Release|x86.Build.0 = Release|Any CPU + {9525A4AA-6731-4AB2-8CD0-ADDF7940FE32}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {9525A4AA-6731-4AB2-8CD0-ADDF7940FE32}.Debug|Any CPU.Build.0 = Debug|Any CPU + {9525A4AA-6731-4AB2-8CD0-ADDF7940FE32}.Debug|x64.ActiveCfg = Debug|Any CPU + {9525A4AA-6731-4AB2-8CD0-ADDF7940FE32}.Debug|x64.Build.0 = Debug|Any CPU + {9525A4AA-6731-4AB2-8CD0-ADDF7940FE32}.Debug|x86.ActiveCfg = Debug|Any CPU + {9525A4AA-6731-4AB2-8CD0-ADDF7940FE32}.Debug|x86.Build.0 = Debug|Any CPU + {9525A4AA-6731-4AB2-8CD0-ADDF7940FE32}.Release|Any CPU.ActiveCfg = Release|Any CPU + {9525A4AA-6731-4AB2-8CD0-ADDF7940FE32}.Release|Any CPU.Build.0 = Release|Any CPU + {9525A4AA-6731-4AB2-8CD0-ADDF7940FE32}.Release|x64.ActiveCfg = Release|Any CPU + {9525A4AA-6731-4AB2-8CD0-ADDF7940FE32}.Release|x64.Build.0 = Release|Any CPU + {9525A4AA-6731-4AB2-8CD0-ADDF7940FE32}.Release|x86.ActiveCfg = Release|Any CPU + {9525A4AA-6731-4AB2-8CD0-ADDF7940FE32}.Release|x86.Build.0 = Release|Any CPU + {71283236-56CB-481E-A644-B7F9AF9EFDF9}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {71283236-56CB-481E-A644-B7F9AF9EFDF9}.Debug|Any CPU.Build.0 = Debug|Any CPU + {71283236-56CB-481E-A644-B7F9AF9EFDF9}.Debug|x64.ActiveCfg = Debug|Any CPU + {71283236-56CB-481E-A644-B7F9AF9EFDF9}.Debug|x64.Build.0 = Debug|Any CPU + {71283236-56CB-481E-A644-B7F9AF9EFDF9}.Debug|x86.ActiveCfg = Debug|Any CPU + {71283236-56CB-481E-A644-B7F9AF9EFDF9}.Debug|x86.Build.0 = Debug|Any CPU + {71283236-56CB-481E-A644-B7F9AF9EFDF9}.Release|Any CPU.ActiveCfg = Release|Any CPU + {71283236-56CB-481E-A644-B7F9AF9EFDF9}.Release|Any CPU.Build.0 = Release|Any CPU + {71283236-56CB-481E-A644-B7F9AF9EFDF9}.Release|x64.ActiveCfg = Release|Any CPU + {71283236-56CB-481E-A644-B7F9AF9EFDF9}.Release|x64.Build.0 = Release|Any CPU + {71283236-56CB-481E-A644-B7F9AF9EFDF9}.Release|x86.ActiveCfg = Release|Any CPU + {71283236-56CB-481E-A644-B7F9AF9EFDF9}.Release|x86.Build.0 = Release|Any CPU + {0B2B697D-DD20-4869-836C-08C848E1813F}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {0B2B697D-DD20-4869-836C-08C848E1813F}.Debug|Any CPU.Build.0 = Debug|Any CPU + {0B2B697D-DD20-4869-836C-08C848E1813F}.Debug|x64.ActiveCfg = Debug|Any CPU + {0B2B697D-DD20-4869-836C-08C848E1813F}.Debug|x64.Build.0 = Debug|Any CPU + {0B2B697D-DD20-4869-836C-08C848E1813F}.Debug|x86.ActiveCfg = Debug|Any CPU + {0B2B697D-DD20-4869-836C-08C848E1813F}.Debug|x86.Build.0 = Debug|Any CPU + {0B2B697D-DD20-4869-836C-08C848E1813F}.Release|Any CPU.ActiveCfg = Release|Any CPU + {0B2B697D-DD20-4869-836C-08C848E1813F}.Release|Any CPU.Build.0 = Release|Any CPU + {0B2B697D-DD20-4869-836C-08C848E1813F}.Release|x64.ActiveCfg = Release|Any CPU + {0B2B697D-DD20-4869-836C-08C848E1813F}.Release|x64.Build.0 = Release|Any CPU + {0B2B697D-DD20-4869-836C-08C848E1813F}.Release|x86.ActiveCfg = Release|Any CPU + {0B2B697D-DD20-4869-836C-08C848E1813F}.Release|x86.Build.0 = Release|Any CPU EndGlobalSection GlobalSection(SolutionProperties) = preSolution HideSolutionNode = FALSE @@ -186,14 +200,15 @@ Global {97E36F9B-145B-41DB-B6CF-E054B010869E} = {A86A6BBD-1122-4993-B472-6A0265E5F2A1} {1AADC6F7-6FF9-4C68-8A26-E507F22B9060} = {5E72F9F6-8DB0-4727-92F3-D05A3CC0348E} {8D061D46-9E59-42B0-91DC-4E380E4AE0BA} = {FBA5D1FE-11EA-4FAE-B88F-7E2E809419C9} - {BF5B6F41-D688-447F-BF81-EA821216F188} = {9328FEED-6E95-4863-BB7B-521D0D02D7FA} {61FB6C20-4541-40D1-AC4B-3ECDACF5F633} = {9328FEED-6E95-4863-BB7B-521D0D02D7FA} - {8BFDB408-D26D-4689-B426-BE45AD195880} = {9328FEED-6E95-4863-BB7B-521D0D02D7FA} - {B30CD716-698A-4DA2-BD1A-C152B16993C0} = {5E72F9F6-8DB0-4727-92F3-D05A3CC0348E} - {4888D6BB-46D9-4519-8758-E13E397AA226} = {5E72F9F6-8DB0-4727-92F3-D05A3CC0348E} {44DFA13C-03C3-4F07-9D78-30F981BFABC5} = {A86A6BBD-1122-4993-B472-6A0265E5F2A1} {866F8FE0-EE58-4D38-8BE7-CBDD19DD1B40} = {D0952F11-B4B6-4AD4-8F72-C35BD6A33D59} {7EFE8058-F772-40EB-8E12-6E88E2A9E19A} = {FBA5D1FE-11EA-4FAE-B88F-7E2E809419C9} + {3C91F949-5187-4CDF-9A5B-AA3C20F7544B} = {9328FEED-6E95-4863-BB7B-521D0D02D7FA} + {8F2F35CB-D5EE-4D92-B42F-BCFFBF9C9D4F} = {5E72F9F6-8DB0-4727-92F3-D05A3CC0348E} + {9525A4AA-6731-4AB2-8CD0-ADDF7940FE32} = {5E72F9F6-8DB0-4727-92F3-D05A3CC0348E} + {71283236-56CB-481E-A644-B7F9AF9EFDF9} = {9328FEED-6E95-4863-BB7B-521D0D02D7FA} + {0B2B697D-DD20-4869-836C-08C848E1813F} = {9328FEED-6E95-4863-BB7B-521D0D02D7FA} EndGlobalSection GlobalSection(ExtensibilityGlobals) = postSolution SolutionGuid = {A0BD3F74-AC23-4649-932F-ECB61CF9EED6} -- Gitee From 54144bd645d5549ae61bebfe4610b75200ba8a49 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E6=96=87=E7=8E=8B=E7=8E=8B?= <596461462@qq.com> Date: Wed, 12 Feb 2020 15:48:04 +0800 Subject: [PATCH 07/19] =?UTF-8?q?readme=E6=9B=B4=E6=96=B0=EF=BC=8C?= =?UTF-8?q?=E4=B8=AD=E9=97=B4=E6=9C=8D=E5=8A=A1=E5=99=A8=E9=87=8D=E6=9E=84?= =?UTF-8?q?=E4=BC=98=E5=8C=96(=E6=9C=AA=E5=AE=8C=E6=88=90)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- README.md | 56 +++++----- .../Helper/MessageHelper.cs | 105 ------------------ SiMay.Net.SessionProvider.Core_/LogHelper.cs | 25 ----- SiMay.Net.SessionProvider.Core_/MsgCommand.cs | 20 ---- .../Properties/AssemblyInfo.cs | 36 ------ .../SiMay.Net.SessionProvider.Core.csproj | 55 --------- SiMay.Net.SessionProvider.Core_/Win32Api.cs | 52 --------- .../Dispatcher/TcpSessionMainConnection.cs | 2 +- 8 files changed, 32 insertions(+), 319 deletions(-) delete mode 100644 SiMay.Net.SessionProvider.Core_/Helper/MessageHelper.cs delete mode 100644 SiMay.Net.SessionProvider.Core_/LogHelper.cs delete mode 100644 SiMay.Net.SessionProvider.Core_/MsgCommand.cs delete mode 100644 SiMay.Net.SessionProvider.Core_/Properties/AssemblyInfo.cs delete mode 100644 SiMay.Net.SessionProvider.Core_/SiMay.Net.SessionProvider.Core.csproj delete mode 100644 SiMay.Net.SessionProvider.Core_/Win32Api.cs diff --git a/README.md b/README.md index b59bcf3..cfcfce4 100644 --- a/README.md +++ b/README.md @@ -1,4 +1,5 @@ -# 系统介绍 + +# 系统介绍 - SiMay远程控制管理系统是一个Windows远程控制系统,底层基于IOCP的异步通信模型,能对海量客户端实时监控,目前功能已实现:远程桌面,基于可视区域逐行扫描算法,仅传输桌面变化区域,可有效节省传输流量;经典的文件管理方式,实现了快速上传下载文件和文件夹;实时传输远程语音与发送语音,及实时捕获远程摄像头;Windows风格界面的经典注册表管理模块;命令行终端;系统进程管理,实时进程查看,用户桌面视图墙轮播等功能,被控服务端支持绿色启动及以系统服务方式安装,解决了WindowsSession桌面切换限制,实现了捕获UAC,WinLogon桌面;系统实现了中间会话服务器,可支持不同平台多主控端同时监控同一被控端,项目完全采用C#.NET开发,代码仅供参考,项目不定时更新,欢迎关注点星星,fork。欢迎入群技术交流:905958449 :laughing: :blush: # 申明 @@ -16,66 +17,71 @@ # 系统项目结构 -### SiMay.Core【公共核心功能】## - - SiMay.Basic--基础通用库 - - SiMay.Core--系统核心统一公共库【统一通讯指令丶共用组件丶通信数据实体等..】 - - SiMay.Serialize--轻量级高性能二进制序列化库【作用:系统通信数据实体化】 +### SiMay.Core【公共核心功能】 + - SiMay.Basic --基础通用库 + - SiMay.Core --系统核心统一公共库【统一通讯指令丶共用组件丶通信数据实体等..】 + - SiMay.Serialize --轻量级高性能二进制序列化库【作用:系统通信数据实体化】 -### SiMay.RemoteMonitor【主控端】## - - SiMay.RemoteControlsCore 主控端核心库 - - SiMay.RemoteMonitor--Windows主控端(基于核心库) +### SiMay.RemoteMonitor【主控端】 + - SiMay.RemoteControlsCore --主控端核心库 + - SiMay.RemoteMonitor --Windows主控端(基于核心库) - SiMay.RemoteMonitorForWeb【计划,未完成】 --Web主控端后端(基于核心库,支持.NET Core),基于WebSocket与前端通信 - SiMay.RemoteMonitorForWebSite【计划,未完成】 --Web监控前端 -### SiMay.RemoteService【远程服务端】## +### SiMay.RemoteService【远程服务端】 - SiMay.RemoteService.Loader --内存加载Loader,实现远程内存载入被控端核心库 - SiMay.ServiceCore --被控端核心库/被控端主程序 -### SiMay.SessionProvider【会话提供库】## - - SiMay.Net.SessionProvider--会话提供库【作用:提供服务器监听模式或者中间会话代理协议】 - - SiMay.Net.SessionProvider.Core--代理协议统一公用库【作用:统一中间库和服务器的通信指令及序列化等】 - - SiMay.Net.SessionProviderService--中间会话代理服务器【作用:提供保持服务端会话保持丶数据转发功能,基于此实现多平台端监控】 +### SiMay.SessionProvider【会话提供库】 + - SiMay.Net.SessionProvider --会话提供库【作用:提供服务器监听模式或者中间会话代理协议】 + - SiMay.Net.SessionProvider.Core --代理协议统一公用库【作用:统一中间库和服务器的通信指令及序列化等】 + - SiMay.Net.SessionProviderService --中间会话代理服务器【作用:提供保持服务端会话保持丶数据转发功能,基于此实现多平台端监控】 -### SiMay.Sockets【Socket通信库】## +### SiMay.Sockets【Socket通信库】 - SiMay.Socket.Standard --轻量级通信引擎 - - SiMaySocketTestApp--通信引擎测试程序 + - SiMaySocketTestApp --通信引擎测试程序 -### SiMay.Web.MonitorService【Web监控服务端,已弃用】## - - SiMay.Net.HttpRemoteMonitorService--WebSocket监控服务端 +### SiMay.Web.MonitorService【Web监控服务端,已弃用】 + - SiMay.Net.HttpRemoteMonitorService --WebSocket监控服务端 ### 编译 -1.Bin为编译目录,重新生成后,主控程序将编译到此目录,Bin->dat目录为被控服务端目录,被控服务端编译后在此。(没有目录新建一下) + - 1.Bin为编译目录,重新生成后,主控程序将编译到此目录,Bin->dat目录为被控服务端目录,被控服务端编译后在此。(没有目录新建一下) ### 运行 -1.局域网 + - 1.局域网 + 主控端:打开位与Bin目录下的主控端程序SiMayRemoteMonitor.exe,确认系统设置服务器地址为0.0.0.0(监听本机所有网卡),端口默认5200,使用会话模式为=本地服务器,然后保存配置重启程序, 重启后日志输出监听成功,即主控端设置正确。 被控服务端创建:打开主控端-->创建客户-->地址输入本机物理地址(或127.0.0.1),端口设置为服务端监听端口(默认5200)-->点击连接测试检查配置是否正确-->创建服务端文件,服务端文件即为配置完成的被控端程序(如提示找不到文件,请检查被控服务程序是否存在[编译步骤是否正确]),双击运行被控服务程序即可在主控端看见服务在线信息,如主控端无在线信息,请检查上述步骤是否配置正确。 -2.广域网 + - 2.广域网 + 条件:需要主控端处于公网环境(或者设置路由内网映射、使用内网映射工具[如花生壳,内网通]),并且开放主控端监听端口(注意检查端口是否开放、防火墙通行规则)。 创建客户端-->被控服务端连接至主控端的公网地址,端口即可 -3.中间服务器部署 + - 3.中间服务器部署 + 条件:需要中间服务器处于公网环境(建议部署在公网服务器,或者设置路由内网映射),并且开放中间服务器监听端口(默认522端口、注意检查端口是否开放、防火墙通行规则)。 主控端设置: 系统设置-->会话服务器地址 输入 中间服务器的公网地址,端口。-->设置会话模式为:中间会话模式-->确认AccessKey与中间服务器Accesskey一致。(中间会话服务器系统设置位于标题栏系统菜单右键)-->创建客户端并选择会话模式为中间会话模式,ip,端输入中间服务器的公网地址即可 -4.web端监控【完善中,不可用】 + - 4.web端监控【完善中,不可用】 + 配置IIS,部署SiMay.WebRemoteMonitor网站,编译启动SiMay.Net.HttpRemoteMonitorService,配置地址指向中间服务器ip,端口即可(无系统设置,需手动配置配置文件),如连接成功,中间服务器出现主控制连接在线日志即可 使用浏览器,访问SiMay.WebRemoteMonitor网站,输入SiMay.Net.HttpRemoteMonitorService配置的账号密码即可,当有中间服务器有被控端会话时,将自动连接至http服务,连接成功后网页可看到被控服务端计算机桌面视图,长按视图可打开更多功能。 ### 技术架构 - - 基于IOCP的异步Socket高性能通信模型 - - 基于实体的实体消息协议 - - 热区域逐行扫描算法的远程桌面 - 基于组件式的系统架构 + - 基于实体的实体消息协议 + - 基于IOCP的异步Socket高性能通信模型 + - 基于可视区域逐行扫描算法的远程桌面 - 基于Windows WaInXX系列实现的语音通讯 - 基于Dx组件捕获摄像头 - 基于HOOK技术的键盘记录 - 基于WebSocket技术实现Web端监控 + - 中间会话服务转发,支持多个主控端同时实时监控 ### 开发环境 - 建议 Visual Studio 2019 企业版 diff --git a/SiMay.Net.SessionProvider.Core_/Helper/MessageHelper.cs b/SiMay.Net.SessionProvider.Core_/Helper/MessageHelper.cs deleted file mode 100644 index 836c8d3..0000000 --- a/SiMay.Net.SessionProvider.Core_/Helper/MessageHelper.cs +++ /dev/null @@ -1,105 +0,0 @@ -using System; -using static SiMay.Serialize.Standard.PacketSerializeHelper; - -namespace SiMay.Net.SessionProviderServiceCore -{ - /// - /// 消息处理帮助(格式:Int16的消息头 + payload) - /// - public static class MessageHelper - { - /// - /// 序列化数据实体,并封装消息头 - /// - /// - /// - /// - public static byte[] CopyMessageHeadTo(T cmd, object entity) - where T : struct - { - return CopyMessageHeadTo(cmd, SerializePacket(entity)); - } - - /// - /// - /// - /// - /// - /// - /// - public static byte[] CopyMessageHeadTo(T cmd, byte[] data, int size) - where T : struct - { - byte[] buff = new byte[size + sizeof(short)]; - BitConverter.GetBytes(Convert.ToInt16(cmd)).CopyTo(buff, 0); - Array.Copy(data, 0, buff, sizeof(Int16), size); - - return buff; - } - - /// - /// 构建消息至数据头部 - /// - /// - /// - /// - public static byte[] CopyMessageHeadTo(T cmd, byte[] data = null) - where T : struct - { - if (data == null) - data = new byte[] { }; - - return CopyMessageHeadTo(cmd, data, data.Length); - } - - /// - /// 构建消息头至数据头部 - /// - /// 消息头 - /// 字符串 - /// - public static byte[] CopyMessageHeadTo(T cmd, string str) - where T : struct - { - byte[] data = str.UnicodeStringToBytes(); - - return CopyMessageHeadTo(cmd, data, data.Length); - } - - /// - /// 获取消息头 - /// - /// - /// - public static T GetMessageHead(this byte[] data) - where T : struct - { - return (T)Enum.ToObject(typeof(T), BitConverter.ToInt16(data, 0)); - } - - /// - /// 获取消息载体 - /// - /// - /// - public static byte[] GetMessagePayload(this byte[] data) - { - byte[] payload = new byte[data.Length - sizeof(short)]; - Array.Copy(data, sizeof(short), payload, 0, payload.Length); - return payload; - } - - /// - /// 反序列化数据实体 - /// - /// - /// - /// - public static T GetMessageEntity(this byte[] data) - where T : new() - { - var entity = DeserializePacket(GetMessagePayload(data)); - return entity; - } - } -} \ No newline at end of file diff --git a/SiMay.Net.SessionProvider.Core_/LogHelper.cs b/SiMay.Net.SessionProvider.Core_/LogHelper.cs deleted file mode 100644 index ae53223..0000000 --- a/SiMay.Net.SessionProvider.Core_/LogHelper.cs +++ /dev/null @@ -1,25 +0,0 @@ -using System; -using System.IO; - -namespace SiMay.Net.SessionProvider.Core -{ - - public class LogHelper - { - - public static void WriteLog(string log, string LogAddress = "") - { - if (LogAddress == "") - LogAddress = Environment.CurrentDirectory + @"\SiMaylog.log"; - - try - { - StreamWriter fs = new StreamWriter(LogAddress, true); - fs.WriteLine(DateTime.Now.ToString() + " " + log); - fs.Close(); - } - catch { } - - } - } -} \ No newline at end of file diff --git a/SiMay.Net.SessionProvider.Core_/MsgCommand.cs b/SiMay.Net.SessionProvider.Core_/MsgCommand.cs deleted file mode 100644 index dcd3b9f..0000000 --- a/SiMay.Net.SessionProvider.Core_/MsgCommand.cs +++ /dev/null @@ -1,20 +0,0 @@ -using System; -using System.Collections.Generic; -using System.Linq; -using System.Text; -using System.Threading.Tasks; - -namespace SiMay.Net.SessionProvider.Core -{ - public enum MsgCommand - { - Msg_Pull_Session,//获取所有主连接 - Msg_Set_Session,//创建Session - Msg_Set_Session_Id,//主连接关联Session - Msg_Close_Session,//Session离线 - Msg_Connect_Work,//发起一个工作连接 - Msg_LogOut,//退出登陆 - Msg_MessageData,//数据 - Msg_AccessKeyWrong//AccessKey错误 - } -} diff --git a/SiMay.Net.SessionProvider.Core_/Properties/AssemblyInfo.cs b/SiMay.Net.SessionProvider.Core_/Properties/AssemblyInfo.cs deleted file mode 100644 index d5f16f2..0000000 --- a/SiMay.Net.SessionProvider.Core_/Properties/AssemblyInfo.cs +++ /dev/null @@ -1,36 +0,0 @@ -using System.Reflection; -using System.Runtime.CompilerServices; -using System.Runtime.InteropServices; - -// 有关程序集的一般信息由以下 -// 控制。更改这些特性值可修改 -// 与程序集关联的信息。 -[assembly: AssemblyTitle("SiMay.Net.SessionProvider.Core")] -[assembly: AssemblyDescription("")] -[assembly: AssemblyConfiguration("")] -[assembly: AssemblyCompany("")] -[assembly: AssemblyProduct("SiMay.Net.SessionProvider.Core")] -[assembly: AssemblyCopyright("Copyright © 2019")] -[assembly: AssemblyTrademark("")] -[assembly: AssemblyCulture("")] - -// 将 ComVisible 设置为 false 会使此程序集中的类型 -//对 COM 组件不可见。如果需要从 COM 访问此程序集中的类型 -//请将此类型的 ComVisible 特性设置为 true。 -[assembly: ComVisible(false)] - -// 如果此项目向 COM 公开,则下列 GUID 用于类型库的 ID -[assembly: Guid("8bfdb408-d26d-4689-b426-be45ad195880")] - -// 程序集的版本信息由下列四个值组成: -// -// 主版本 -// 次版本 -// 生成号 -// 修订号 -// -// 可以指定所有值,也可以使用以下所示的 "*" 预置版本号和修订号 -//通过使用 "*",如下所示: -// [assembly: AssemblyVersion("1.0.*")] -[assembly: AssemblyVersion("1.0.0.0")] -[assembly: AssemblyFileVersion("1.0.0.0")] diff --git a/SiMay.Net.SessionProvider.Core_/SiMay.Net.SessionProvider.Core.csproj b/SiMay.Net.SessionProvider.Core_/SiMay.Net.SessionProvider.Core.csproj deleted file mode 100644 index 96ee0a0..0000000 --- a/SiMay.Net.SessionProvider.Core_/SiMay.Net.SessionProvider.Core.csproj +++ /dev/null @@ -1,55 +0,0 @@ - - - - - Debug - AnyCPU - {8BFDB408-D26D-4689-B426-BE45AD195880} - Library - Properties - SiMay.Net.SessionProvider.Core - SiMay.Net.SessionProvider.Core - v4.6.1 - 512 - - - - true - full - false - bin\Debug\ - DEBUG;TRACE - prompt - 4 - 8.0 - false - - - pdbonly - true - bin\Release\ - TRACE - prompt - 4 - 8.0 - false - - - - - - - - - - - - - - - - - - - - \ No newline at end of file diff --git a/SiMay.Net.SessionProvider.Core_/Win32Api.cs b/SiMay.Net.SessionProvider.Core_/Win32Api.cs deleted file mode 100644 index 37600b9..0000000 --- a/SiMay.Net.SessionProvider.Core_/Win32Api.cs +++ /dev/null @@ -1,52 +0,0 @@ -using System; -using System.Collections.Generic; -using System.Drawing; -using System.Linq; -using System.Runtime.InteropServices; -using System.Text; - -namespace SiMay.Net.SessionProvider.Core -{ - public class Win32Api - { - [DllImport("user32.dll")] - public static extern IntPtr GetSystemMenu(IntPtr hWnd, bool bRevert);//获取窗体系统菜单 - [DllImport("user32.dll")] - - - public static extern bool InsertMenu(IntPtr hMenu, Int32 wPosition, Int32 wFlags, Int32 wIDNewItem, string lpNewItem);//插入菜单 - - [DllImport("user32.dll", CallingConvention = CallingConvention.StdCall)] - public static extern bool RemoveMenu(IntPtr hMenu, uint nPosition, uint nFlags);//删除菜单 - - [DllImport("user32.dll", CallingConvention = CallingConvention.StdCall)] - private static extern bool SetMenuItemBitmaps(IntPtr hMenu, Int32 nPosition, Int32 nFlags, Bitmap pBmpUnchecked, Bitmap pBmpchecked);//设置菜单图片 - - - [DllImport("user32.dll", CallingConvention = CallingConvention.StdCall)] - public static extern bool InsertMenuItem(IntPtr hMenu, Int32 uItem, Int32 lpMenuItemInfo, bool fByPos);//插入菜单 - - - [DllImport("user32.dll", CallingConvention = CallingConvention.StdCall)] - public static extern bool AppendMenu(IntPtr hMenu, Int32 nFlags, Int32 IDNewItem, string lpNewItem);//追加菜单 - - [DllImport("user32.dll")] - public static extern ulong CheckMenuItem(IntPtr hmenu, uint uIDCheckItem, uint uCheck);//设置菜单勾选 - - [DllImport("user32.dll")] - public static extern bool EnableMenuItem(IntPtr hmenu, uint uIDEnableItem, uint wEnable);//设置菜单可用 - - - public const Int32 MF_SEPARATOR = 0x800; - public const Int32 MF_BYPOSITION = 0x400; - public const Int32 MF_STRING = 0x0; - public const Int32 MF_REMOVE = 0x1000; - - public const int WM_SYSCOMMAND = 0x112; - - public const uint MF_ENABLED = 0; - public const uint MF_DISABLED = (uint)0x00000002L; - public const uint MF_UNCHECKED = 0; - public const uint MF_CHECKED = (uint)0x00000008L; - } -} diff --git a/SiMay.Net.SessionProviderServiceCore/Dispatcher/TcpSessionMainConnection.cs b/SiMay.Net.SessionProviderServiceCore/Dispatcher/TcpSessionMainConnection.cs index 1062586..386acde 100644 --- a/SiMay.Net.SessionProviderServiceCore/Dispatcher/TcpSessionMainConnection.cs +++ b/SiMay.Net.SessionProviderServiceCore/Dispatcher/TcpSessionMainConnection.cs @@ -40,7 +40,7 @@ namespace SiMay.Net.SessionProviderServiceCore } TcpSessionChannelDispatcher dispatcher; - if (_dispatchers.TryGetValue((int)_accessId.Value, out dispatcher) || true) + if (_dispatchers.TryGetValue(_accessId.Value, out dispatcher) || true) { var calculateOffsetLength = (_packageLength.Value + defineHeadSize) - _transpondOffset; if (ListByteBuffer.Count <= calculateOffsetLength) -- Gitee From 87acd4def2f99c0d038affbece76e45224842731 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E6=96=87=E7=8E=8B=E7=8E=8B?= <596461462@qq.com> Date: Sun, 16 Feb 2020 15:18:02 +0800 Subject: [PATCH 08/19] =?UTF-8?q?=E4=B8=AD=E9=97=B4=E6=9C=8D=E5=8A=A1?= =?UTF-8?q?=E5=99=A8=E5=AE=8C=E6=88=90?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- README.md | 10 +- SiMay.Basic/ArrayHelper.cs | 16 + SiMay.Basic/CollectionExtension.cs | 39 ++ SiMay.Basic/{IPHelper.cs => HostHelper.cs} | 2 +- SiMay.Core/Entitys/ServiceOptions.cs | 5 +- SiMay.Core/Enums/ConnectionWorkType.cs | 2 +- SiMay.Core/Packets/AckPack.cs | 6 +- SiMay.Core/SiMay.Core.csproj | 4 + .../Entitys/AckPacket.cs | 2 +- .../Enums/ConnectionWorkType.cs | 5 + .../Extension/MessagePacketExtension.cs | 19 + .../Helper/LogHelper.cs | 100 ++++ .../Helper/MessageHelper.cs | 8 +- .../SiMay.Net.SessionProvider.Core.csproj | 1 + .../Delegate/NetNotifyEventHandler.cs | 9 - .../Delegate/ProxyNotifyEventHandler.cs | 9 - .../ProxyProviderNotify.cs} | 10 +- .../{ => Enum}/SessionProviderType.cs | 0 .../LogOutEventArgs.cs} | 12 +- SiMay.Net.SessionProvider/MessageHelper.cs | 32 - .../{ => Providers}/SessionProvider.cs | 33 +- .../Providers/TcpProxySessionProvider.cs | 270 +++++++++ .../TcpProxySessionProviderHandle.cs | 456 -------------- ...rHandle.cs => TcpSocketSessionProvider.cs} | 75 +-- .../SessionBased/TcpProxySessionBased.cs | 108 ---- .../SessionBased/TcpSocketSessionBased.cs | 50 -- .../SessionProviderFactory.cs | 22 +- .../SessionProviderOptions.cs | 31 +- .../{SessionWorkType.cs => SysContanct.cs} | 7 +- .../SessionProviderContext.cs | 49 +- .../TcpProxyApplicationConnectionContext.cs | 109 ++++ .../TcpProxyMainConnectionContext.cs | 145 +++++ .../TcpSocketSessionContext.cs | 64 ++ .../AccessKeyExamine.cs | 26 - SiMay.Net.SessionProviderService/App.config | 2 +- .../ApplicationConfiguration.cs | 68 ++- .../ChannelViewItem/ChannelViewItem.cs | 48 ++ .../TcpChannelContextNotifyHandler.cs | 11 - .../LogShowQueueHelper.cs | 28 - .../MessageHelper.cs | 26 - .../Notify/ManagerChannelNotify.cs | 13 - .../ChannelListViewItem.cs | 18 - SiMay.Net.SessionProviderService/Program.cs | 4 +- .../SessionProviderService.Designer.cs | 140 +++-- .../SessionProviderService.cs | 561 +++--------------- .../SessionProviderService.resx | 3 + .../SiMay.Net.SessionProviderService.csproj | 33 +- .../SysContact.cs | 14 - ...ner.cs => SystemOptionsDialog.Designer.cs} | 155 ++++- ...ptionsDialog.cs => SystemOptionsDialog.cs} | 41 +- ...nsDialog.resx => SystemOptionsDialog.resx} | 0 .../TcpChannelContextServiceType.cs | 17 - .../TcpSessionChannelContext.cs | 302 ---------- SiMay.Net.SessionProviderService/Win32.cs | 53 ++ .../ApplicationConfiguartion.cs | 27 +- .../Dispatcher/ApportionDispatcher.cs | 52 +- .../TcpSessionApplicationWorkerConnection.cs | 3 + .../TcpSessionMainApplicationConnection.cs | 33 +- .../Dispatcher/TcpSessionMainConnection.cs | 50 +- .../DispatcherBase/DispatcherBase.cs | 28 +- .../TcpSessionChannelDispatcher.cs | 18 +- .../Enums/LogOutLevelType.cs | 24 + .../Extension/CreateDispatcherExtension.cs | 6 +- .../MainSessionProviderService.cs | 144 +++-- .../MainService/MainService.cs | 34 +- SiMay.RemoteClient.NewCore/Program.cs | 10 +- .../ServiceBase/ApplicationProtocolService.cs | 5 +- .../TrunkService/Service.cs | 10 +- .../TrunkService/UserTrunkContext.cs | 10 +- .../ApplicationAdapterHandler.cs | 2 +- .../ApplicationProtocolAdapterHandler.cs | 4 +- .../MainApplicationAdapterHandler.cs | 2 +- SiMay.RemoteControlsCore/AppConfiguration.cs | 34 +- .../AudioAdapterHandler.cs | 2 +- .../KeyboardAdapterHandler.cs | 2 +- .../RegistryEditorAdapterHandler.cs | 2 +- .../RemoteFileAdapterHandler.cs | 2 +- .../RemoteScreenAdapterHandler.cs | 2 +- .../ShellAdapterHandler.cs | 2 +- .../StartupAdapterHandler.cs | 2 +- .../SystemAdapterHandler.cs | 2 +- .../TcpConnectionAdapterHandler.cs | 2 +- .../VideoAppAdapterHandler.cs | 2 +- .../Entitys/SessionSyncContext.cs | 2 +- .../MainApplicationAdapterHandler.cs | 67 ++- .../SiMay.RemoteControlsCore.csproj | 4 + .../Application/ScreenApplication.cs | 1 - .../AppSettingForm.Designer.cs | 227 ++++--- .../MainApplication/AppSettingForm.cs | 20 +- .../MainApplication/BuilderServiceForm.cs | 2 +- .../MainApplication/MainApplication.cs | 17 +- .../UserControls/USessionListItem.cs | 2 +- SiMay.RemoteMonitor/Win32Api.cs | 3 +- .../Interface/IAppMainService.cs | 2 +- SiMay.RemoteService.Loader/Program.cs | 12 +- .../DynamicMethodMemberAccessor.cs | 3 +- .../Tcp/Client/TcpSocketSaeaClientAgent.cs | 6 +- .../Tcp/Server/TcpSocketSaeaServer.cs | 4 +- .../Tcp/Session/TcpSocketSaeaFullBased.cs | 8 +- .../Tcp/Session/TcpSocketSaeaPackBased.cs | 13 +- .../Tcp/Session/TcpSocketSaeaSession.cs | 4 +- .../Tcp/TcpSocketCompletionNotify.cs | 2 +- .../Tcp/TcpSocketSaeaEngineBased.cs | 4 +- .../Tcp/TcpSocketsFactory.cs | 4 +- 104 files changed, 2045 insertions(+), 2151 deletions(-) create mode 100644 SiMay.Basic/ArrayHelper.cs rename SiMay.Basic/{IPHelper.cs => HostHelper.cs} (94%) create mode 100644 SiMay.Net.SessionProvider.Core/Extension/MessagePacketExtension.cs create mode 100644 SiMay.Net.SessionProvider.Core/Helper/LogHelper.cs delete mode 100644 SiMay.Net.SessionProvider/Delegate/NetNotifyEventHandler.cs delete mode 100644 SiMay.Net.SessionProvider/Delegate/ProxyNotifyEventHandler.cs rename SiMay.Net.SessionProvider/{Notify/ProxyNotify.cs => Enum/ProxyProviderNotify.cs} (35%) rename SiMay.Net.SessionProvider/{ => Enum}/SessionProviderType.cs (100%) rename SiMay.Net.SessionProvider/{Notify/SessionCompletedNotify.cs => EventArgs/LogOutEventArgs.cs} (30%) delete mode 100644 SiMay.Net.SessionProvider/MessageHelper.cs rename SiMay.Net.SessionProvider/{ => Providers}/SessionProvider.cs (37%) create mode 100644 SiMay.Net.SessionProvider/Providers/TcpProxySessionProvider.cs delete mode 100644 SiMay.Net.SessionProvider/Providers/TcpProxySessionProviderHandle.cs rename SiMay.Net.SessionProvider/Providers/{TcpSocketSessionProviderHandle.cs => TcpSocketSessionProvider.cs} (32%) delete mode 100644 SiMay.Net.SessionProvider/SessionBased/TcpProxySessionBased.cs delete mode 100644 SiMay.Net.SessionProvider/SessionBased/TcpSocketSessionBased.cs rename SiMay.Net.SessionProvider/{SessionWorkType.cs => SysContanct.cs} (51%) rename SiMay.Net.SessionProvider/{SessionBased => TcpSessionConnection}/SessionProviderContext.cs (40%) create mode 100644 SiMay.Net.SessionProvider/TcpSessionConnection/TcpProxyApplicationConnectionContext.cs create mode 100644 SiMay.Net.SessionProvider/TcpSessionConnection/TcpProxyMainConnectionContext.cs create mode 100644 SiMay.Net.SessionProvider/TcpSessionConnection/TcpSocketSessionContext.cs delete mode 100644 SiMay.Net.SessionProviderService/AccessKeyExamine.cs create mode 100644 SiMay.Net.SessionProviderService/ChannelViewItem/ChannelViewItem.cs delete mode 100644 SiMay.Net.SessionProviderService/Delagate/TcpChannelContextNotifyHandler.cs delete mode 100644 SiMay.Net.SessionProviderService/LogShowQueueHelper.cs delete mode 100644 SiMay.Net.SessionProviderService/MessageHelper.cs delete mode 100644 SiMay.Net.SessionProviderService/Notify/ManagerChannelNotify.cs delete mode 100644 SiMay.Net.SessionProviderService/OnChannelListViewItem/ChannelListViewItem.cs delete mode 100644 SiMay.Net.SessionProviderService/SysContact.cs rename SiMay.Net.SessionProviderService/{AppOptionsDialog.Designer.cs => SystemOptionsDialog.Designer.cs} (50%) rename SiMay.Net.SessionProviderService/{AppOptionsDialog.cs => SystemOptionsDialog.cs} (39%) rename SiMay.Net.SessionProviderService/{AppOptionsDialog.resx => SystemOptionsDialog.resx} (100%) delete mode 100644 SiMay.Net.SessionProviderService/TcpChannelContextServiceType.cs delete mode 100644 SiMay.Net.SessionProviderService/TcpSessionChannelContext.cs create mode 100644 SiMay.Net.SessionProviderService/Win32.cs create mode 100644 SiMay.Net.SessionProviderServiceCore/Enums/LogOutLevelType.cs diff --git a/README.md b/README.md index cfcfce4..b85c95a 100644 --- a/README.md +++ b/README.md @@ -6,7 +6,7 @@ - 作为创作者,我对由此软件引起的任何行为和/或损害不承担任何责任。 您对自己的行为承担全部责任,并承认此软件仅用于教育和研究目的。 不得用于您不拥有或有权使用的任何系统。 使用此软件,您自动同意上述内容,感谢支持。 # 背景 - - 项目仅是个人技术总结项目,总结在工作中所遇到的有趣技术,测试新技术,比如系统架构,语法等。经过几次重构,系统相对比较成熟了,决定开源反馈开源社区,希望更多人能和我一起进步,欢迎吐槽改进。 + - 仅是个人项目,总结在工作中所遇到的有趣技术,新技术,新语法等,系统架构等,经过几次重构,系统相对比较成熟了,决定开源反馈开源社区,希望更多人能和我一起进步,欢迎吐槽改进。 ![主控界面](https://images.gitee.com/uploads/images/2019/0717/225727_cc5c40c8_1654743.jpeg "主控制界面") ![创建服务端](https://images.gitee.com/uploads/images/2019/0717/225801_d0ccad61_1654743.jpeg "创建服务端") @@ -22,22 +22,22 @@ - SiMay.Core --系统核心统一公共库【统一通讯指令丶共用组件丶通信数据实体等..】 - SiMay.Serialize --轻量级高性能二进制序列化库【作用:系统通信数据实体化】 -### SiMay.RemoteMonitor【主控端】 +### SiMay.RemoteMonitor【主控制端】 - SiMay.RemoteControlsCore --主控端核心库 - SiMay.RemoteMonitor --Windows主控端(基于核心库) - SiMay.RemoteMonitorForWeb【计划,未完成】 --Web主控端后端(基于核心库,支持.NET Core),基于WebSocket与前端通信 - SiMay.RemoteMonitorForWebSite【计划,未完成】 --Web监控前端 -### SiMay.RemoteService【远程服务端】 +### SiMay.RemoteService【远程被控服务端】 - SiMay.RemoteService.Loader --内存加载Loader,实现远程内存载入被控端核心库 - SiMay.ServiceCore --被控端核心库/被控端主程序 -### SiMay.SessionProvider【会话提供库】 +### SiMay.SessionProvider【会话提供层】 - SiMay.Net.SessionProvider --会话提供库【作用:提供服务器监听模式或者中间会话代理协议】 - SiMay.Net.SessionProvider.Core --代理协议统一公用库【作用:统一中间库和服务器的通信指令及序列化等】 - SiMay.Net.SessionProviderService --中间会话代理服务器【作用:提供保持服务端会话保持丶数据转发功能,基于此实现多平台端监控】 -### SiMay.Sockets【Socket通信库】 +### SiMay.Sockets【通信层】 - SiMay.Socket.Standard --轻量级通信引擎 - SiMaySocketTestApp --通信引擎测试程序 diff --git a/SiMay.Basic/ArrayHelper.cs b/SiMay.Basic/ArrayHelper.cs new file mode 100644 index 0000000..50ebf57 --- /dev/null +++ b/SiMay.Basic/ArrayHelper.cs @@ -0,0 +1,16 @@ +using System; +using System.Collections.Generic; +using System.Text; + +namespace SiMay.Basic +{ + public static class ArrayHelper + { + public static T[] Copy(this T[] source, int offset, int lenght) + { + var nArray = new T[lenght]; + Array.Copy(source, offset, nArray, 0, lenght); + return nArray; + } + } +} diff --git a/SiMay.Basic/CollectionExtension.cs b/SiMay.Basic/CollectionExtension.cs index 73e34ef..ebd4653 100644 --- a/SiMay.Basic/CollectionExtension.cs +++ b/SiMay.Basic/CollectionExtension.cs @@ -1,4 +1,5 @@ using System; +using System.Collections; using System.Collections.Generic; using System.Linq; using System.Text; @@ -11,5 +12,43 @@ namespace SiMay.Basic { return source == null || source.Count == 0; } + + public static T FristOrDefault(this ICollection source, Func func) + { + foreach (var item in source) + { + if (func(item)) + return item; + } + return default; + } + + public static T FristOrDefault(this ICollection source) + { + foreach (var item in source) + { + return (T)item; + } + return default; + } + + public static T FristOrDefault(this ICollection source, Func func) + { + foreach (var item in source) + { + if (func((T)item)) + return (T)item; + } + return default; + } + + public static IEnumerable Select(this ICollection source, Func func) + { + var results = new List(); + foreach (var item in source) + results.Add(func((T)item)); + + return results; + } } } diff --git a/SiMay.Basic/IPHelper.cs b/SiMay.Basic/HostHelper.cs similarity index 94% rename from SiMay.Basic/IPHelper.cs rename to SiMay.Basic/HostHelper.cs index 46fd274..c30f821 100644 --- a/SiMay.Basic/IPHelper.cs +++ b/SiMay.Basic/HostHelper.cs @@ -6,7 +6,7 @@ using System.Text; namespace SiMay.Basic { - public class IPHelper + public class HostHelper { public static string GetHostByName(string host) { diff --git a/SiMay.Core/Entitys/ServiceOptions.cs b/SiMay.Core/Entitys/ServiceOptions.cs index 2ac6004..425c277 100644 --- a/SiMay.Core/Entitys/ServiceOptions.cs +++ b/SiMay.Core/Entitys/ServiceOptions.cs @@ -1,11 +1,12 @@ -using System; +using SiMay.ReflectCache; +using System; using System.Collections.Generic; using System.Linq; using System.Text; namespace SiMay.Core.Entitys { - public class ServiceOptions + public class ServiceOptions : EntitySerializerBase { public string Id { get; set; } public string Host { get; set; } diff --git a/SiMay.Core/Enums/ConnectionWorkType.cs b/SiMay.Core/Enums/ConnectionWorkType.cs index 9bee62d..9138085 100644 --- a/SiMay.Core/Enums/ConnectionWorkType.cs +++ b/SiMay.Core/Enums/ConnectionWorkType.cs @@ -3,7 +3,7 @@ using System.Collections.Generic; using System.Linq; using System.Text; -namespace SiMay.Core.Enums +namespace SiMay.Core { public enum ConnectionWorkType : Byte { diff --git a/SiMay.Core/Packets/AckPack.cs b/SiMay.Core/Packets/AckPack.cs index 8fe2181..c3ba569 100644 --- a/SiMay.Core/Packets/AckPack.cs +++ b/SiMay.Core/Packets/AckPack.cs @@ -1,5 +1,4 @@ -using SiMay.Core.Enums; -using SiMay.ReflectCache; +using SiMay.ReflectCache; using System; using System.Collections.Generic; using System.Linq; @@ -9,9 +8,8 @@ namespace SiMay.Core.Packets { public class AckPack : EntitySerializerBase { - public ConnectionWorkType Type { get; set; } + public byte Type { get; set; } public long AccessId { get; set; } public long AccessKey { get; set; } - } } diff --git a/SiMay.Core/SiMay.Core.csproj b/SiMay.Core/SiMay.Core.csproj index 4ad0742..eab07be 100644 --- a/SiMay.Core/SiMay.Core.csproj +++ b/SiMay.Core/SiMay.Core.csproj @@ -166,6 +166,10 @@ {8f2f35cb-d5ee-4d92-b42f-bcffbf9c9d4f} SiMay.Basic + + {0B2B697D-DD20-4869-836C-08C848E1813F} + SiMay.Net.SessionProvider.Core + {9525a4aa-6731-4ab2-8cd0-addf7940fe32} SiMay.Serialize.Standard diff --git a/SiMay.Net.SessionProvider.Core/Entitys/AckPacket.cs b/SiMay.Net.SessionProvider.Core/Entitys/AckPacket.cs index c4f1cca..5c63083 100644 --- a/SiMay.Net.SessionProvider.Core/Entitys/AckPacket.cs +++ b/SiMay.Net.SessionProvider.Core/Entitys/AckPacket.cs @@ -8,7 +8,7 @@ namespace SiMay.Net.SessionProvider.Core { public class AckPacket : EntitySerializerBase { - public ConnectionWorkType Type { get; set; } + public byte Type { get; set; } public long AccessId { get; set; } public long AccessKey { get; set; } } diff --git a/SiMay.Net.SessionProvider.Core/Enums/ConnectionWorkType.cs b/SiMay.Net.SessionProvider.Core/Enums/ConnectionWorkType.cs index d452dee..87d127b 100644 --- a/SiMay.Net.SessionProvider.Core/Enums/ConnectionWorkType.cs +++ b/SiMay.Net.SessionProvider.Core/Enums/ConnectionWorkType.cs @@ -10,26 +10,31 @@ namespace SiMay.Net.SessionProvider.Core /// /// 主被控服务连接 /// + [Description("主服务连接")] MainServiceConnection, /// /// 服务工作连接 /// + [Description("应用服务连接")] ApplicationServiceConnection, /// /// 主控端连接 /// + [Description("主控端连接")] MainApplicationConnection, /// /// 应用工作连接 /// + [Description("应用连接")] ApplicationConnection, /// /// 未识别 /// + [Description("未知连接")] None } } diff --git a/SiMay.Net.SessionProvider.Core/Extension/MessagePacketExtension.cs b/SiMay.Net.SessionProvider.Core/Extension/MessagePacketExtension.cs new file mode 100644 index 0000000..e2457b3 --- /dev/null +++ b/SiMay.Net.SessionProvider.Core/Extension/MessagePacketExtension.cs @@ -0,0 +1,19 @@ +using System; +using System.Collections.Generic; +using System.Text; + +namespace SiMay.Net.SessionProvider.Core +{ + public static class MessagePacketExtension + { + public static byte[] BuilderHeadPacket(this byte[] data) + { + int defineHeadSize = sizeof(int); + var builderHeadBytes = new byte[data.Length + defineHeadSize]; + BitConverter.GetBytes(data.Length).CopyTo(builderHeadBytes, 0); + data.CopyTo(builderHeadBytes, defineHeadSize); + + return builderHeadBytes; + } + } +} diff --git a/SiMay.Net.SessionProvider.Core/Helper/LogHelper.cs b/SiMay.Net.SessionProvider.Core/Helper/LogHelper.cs new file mode 100644 index 0000000..76b6a55 --- /dev/null +++ b/SiMay.Net.SessionProvider.Core/Helper/LogHelper.cs @@ -0,0 +1,100 @@ +using SiMay.Basic; +using System; +using System.Collections.Generic; +using System.Diagnostics; +using System.IO; +using System.Text; +using System.Threading; + +namespace SiMay.Net.SessionProvider.Core +{ + + public class LogHelper : IDisposable + { + public static string fileName = Path.Combine(AppDomain.CurrentDomain.BaseDirectory, "SiMaylog.log"); + + static bool _isDisposed = false; + static object _lock = new object(); + static Queue _logQueue = new Queue(); + static ManualResetEvent _event = new ManualResetEvent(false); + static LogHelper() + { + ThreadHelper.CreateThread(() => + { + while (!_isDisposed) + { + _event.WaitOne(); + lock (_lock) + { + var logs = _logQueue.ToArray(); + _logQueue.Clear(); + if (!logs.IsNullOrEmpty()) + Write(logs, fileName); + } + _event.Reset(); + Thread.Sleep(100);//缓存一下 + } + }, true); + } + + public static void WriteErrorByCurrentMethod(Exception ex) + { + StackFrame frame = new StackFrame(1, false); + StringBuilder sb = new StringBuilder(); + sb.AppendLine("DateTime:" + DateTime.Now.ToString()); + sb.AppendLine("Method:" + frame.GetMethod().Name); + sb.AppendLine("Exception Message:" + ex.Message); + sb.AppendLine("StackTrace:" + ex.StackTrace); + _logQueue.Enqueue(sb.ToString()); + _event.Set(); + } + + public static void WriteErrorByCurrentMethod(string log) + { + StackFrame frame = new StackFrame(1, false); + StringBuilder sb = new StringBuilder(); + sb.AppendLine("DateTime:" + DateTime.Now.ToString()); + sb.AppendLine("Method:" + frame.GetMethod().Name); + sb.AppendLine("Log:" + log); + _logQueue.Enqueue(sb.ToString()); + _event.Set(); + } + + public static void WriteLog(string log, string path) + { + StringBuilder sb = new StringBuilder(); + sb.AppendLine("DateTime:" + DateTime.Now.ToString()); + sb.AppendLine("Log:" + log); + Write(new string[] { sb.ToString() }, path); + } + + public static void DebugWriteLog(string log) + { +#if DEBUG + log = "DateTime:" + DateTime.Now.ToString() + " - " + log; + Console.WriteLine(log); + _logQueue.Enqueue(log); + _event.Set(); +#endif + } + + public static void Write(string[] logs, string path) + { + try + { + StreamWriter fs = new StreamWriter(path, true); + foreach (var log in logs) + fs.WriteLine(log); + fs.Close(); + } + catch { } + + } + + public void Dispose() + { + _isDisposed = true; + _event.Set(); + } + } +} \ No newline at end of file diff --git a/SiMay.Net.SessionProvider.Core/Helper/MessageHelper.cs b/SiMay.Net.SessionProvider.Core/Helper/MessageHelper.cs index 7162457..785a11d 100644 --- a/SiMay.Net.SessionProvider.Core/Helper/MessageHelper.cs +++ b/SiMay.Net.SessionProvider.Core/Helper/MessageHelper.cs @@ -27,12 +27,12 @@ namespace SiMay.Net.SessionProvider.Core /// /// /// - public static byte[] CopyMessageHeadTo(T cmd, byte[] data, int size) + public static byte[] CopyMessageHeadTo(T cmd, byte[] data, int offset, int size) where T : struct { byte[] buff = new byte[size + sizeof(short)]; BitConverter.GetBytes(Convert.ToInt16(cmd)).CopyTo(buff, 0); - Array.Copy(data, 0, buff, sizeof(Int16), size); + Array.Copy(data, 0, buff, sizeof(Int16) + offset, size); return buff; } @@ -49,7 +49,7 @@ namespace SiMay.Net.SessionProvider.Core if (data == null) data = new byte[] { }; - return CopyMessageHeadTo(cmd, data, data.Length); + return CopyMessageHeadTo(cmd, data, 0, data.Length); } /// @@ -63,7 +63,7 @@ namespace SiMay.Net.SessionProvider.Core { byte[] data = str.UnicodeStringToBytes(); - return CopyMessageHeadTo(cmd, data, data.Length); + return CopyMessageHeadTo(cmd, data, 0, data.Length); } /// diff --git a/SiMay.Net.SessionProvider.Core/SiMay.Net.SessionProvider.Core.csproj b/SiMay.Net.SessionProvider.Core/SiMay.Net.SessionProvider.Core.csproj index 01dfafc..1806e6c 100644 --- a/SiMay.Net.SessionProvider.Core/SiMay.Net.SessionProvider.Core.csproj +++ b/SiMay.Net.SessionProvider.Core/SiMay.Net.SessionProvider.Core.csproj @@ -9,6 +9,7 @@ + diff --git a/SiMay.Net.SessionProvider/Delegate/NetNotifyEventHandler.cs b/SiMay.Net.SessionProvider/Delegate/NetNotifyEventHandler.cs deleted file mode 100644 index ea9ec86..0000000 --- a/SiMay.Net.SessionProvider/Delegate/NetNotifyEventHandler.cs +++ /dev/null @@ -1,9 +0,0 @@ -using System; -using System.Collections.Generic; -using System.Linq; -using System.Text; - -namespace SiMay.Net.SessionProvider.Delegate -{ - public delegate void OnSessionNotify(TEvent e, Session session); -} diff --git a/SiMay.Net.SessionProvider/Delegate/ProxyNotifyEventHandler.cs b/SiMay.Net.SessionProvider/Delegate/ProxyNotifyEventHandler.cs deleted file mode 100644 index 1b45ffa..0000000 --- a/SiMay.Net.SessionProvider/Delegate/ProxyNotifyEventHandler.cs +++ /dev/null @@ -1,9 +0,0 @@ -using System; -using System.Collections.Generic; -using System.Linq; -using System.Text; - -namespace SiMay.Net.SessionProvider.Delegate -{ - public delegate void OnProxyNotify(TEvent arg); -} diff --git a/SiMay.Net.SessionProvider/Notify/ProxyNotify.cs b/SiMay.Net.SessionProvider/Enum/ProxyProviderNotify.cs similarity index 35% rename from SiMay.Net.SessionProvider/Notify/ProxyNotify.cs rename to SiMay.Net.SessionProvider/Enum/ProxyProviderNotify.cs index 5822ee6..006d5d2 100644 --- a/SiMay.Net.SessionProvider/Notify/ProxyNotify.cs +++ b/SiMay.Net.SessionProvider/Enum/ProxyProviderNotify.cs @@ -1,13 +1,17 @@ using System; using System.Collections.Generic; +using System.ComponentModel; using System.Linq; using System.Text; -namespace SiMay.Net.SessionProvider.Notify +namespace SiMay.Net.SessionProvider { - public enum ProxyNotify + public enum ProxyProviderNotify { - AccessKeyWrong, + [Description("AccessId、Key验证不通过")] + AccessIdOrKeyWrong, + + [Description("登出")] LogOut } } diff --git a/SiMay.Net.SessionProvider/SessionProviderType.cs b/SiMay.Net.SessionProvider/Enum/SessionProviderType.cs similarity index 100% rename from SiMay.Net.SessionProvider/SessionProviderType.cs rename to SiMay.Net.SessionProvider/Enum/SessionProviderType.cs diff --git a/SiMay.Net.SessionProvider/Notify/SessionCompletedNotify.cs b/SiMay.Net.SessionProvider/EventArgs/LogOutEventArgs.cs similarity index 30% rename from SiMay.Net.SessionProvider/Notify/SessionCompletedNotify.cs rename to SiMay.Net.SessionProvider/EventArgs/LogOutEventArgs.cs index 1b33a7d..5a1fdd0 100644 --- a/SiMay.Net.SessionProvider/Notify/SessionCompletedNotify.cs +++ b/SiMay.Net.SessionProvider/EventArgs/LogOutEventArgs.cs @@ -1,16 +1,12 @@ using System; using System.Collections.Generic; -using System.Linq; using System.Text; -namespace SiMay.Net.SessionProvider.Notify +namespace SiMay.Net.SessionProvider { - public enum SessionCompletedNotify + public class LogOutEventArgs : EventArgs { - OnConnected, - OnSend, - OnRecv, - OnReceived, - OnClosed + public string Message { get; private set; } + public LogOutEventArgs(string message) => Message = message; } } diff --git a/SiMay.Net.SessionProvider/MessageHelper.cs b/SiMay.Net.SessionProvider/MessageHelper.cs deleted file mode 100644 index aadce35..0000000 --- a/SiMay.Net.SessionProvider/MessageHelper.cs +++ /dev/null @@ -1,32 +0,0 @@ -using SiMay.Net.SessionProvider.Core; -using SiMay.Sockets.Tcp; -using SiMay.Sockets.Tcp.Session; -using System; -using System.Collections.Generic; -using System.Linq; -using System.Text; - -namespace SiMay.Net.SessionProvider -{ - public class MessageHelper - { - public static byte[] BuilderHeadMessage(byte[] body) - { - var dataBuilder = new List(); - dataBuilder.AddRange(BitConverter.GetBytes(body.Length)); - dataBuilder.AddRange(body); - return dataBuilder.ToArray(); - } - public static void SendMessage(TcpSocketSaeaSession session, MessageHead cmd, byte[] body = null) - { - if (body == null) - body = new byte[] { 0 }; - - byte[] bytes = new byte[sizeof(Int32) + body.Length + 1]; - BitConverter.GetBytes(body.Length + 1).CopyTo(bytes, 0); - bytes[4] = (byte)cmd; - body.CopyTo(bytes, 5); - session.SendAsync(bytes); - } - } -} diff --git a/SiMay.Net.SessionProvider/SessionProvider.cs b/SiMay.Net.SessionProvider/Providers/SessionProvider.cs similarity index 37% rename from SiMay.Net.SessionProvider/SessionProvider.cs rename to SiMay.Net.SessionProvider/Providers/SessionProvider.cs index 746b38c..3ca847e 100644 --- a/SiMay.Net.SessionProvider/SessionProvider.cs +++ b/SiMay.Net.SessionProvider/Providers/SessionProvider.cs @@ -1,6 +1,4 @@ -using SiMay.Net.SessionProvider.Delegate; -using SiMay.Net.SessionProvider.Notify; -using SiMay.Net.SessionProvider.SessionBased; +using SiMay.Sockets.Tcp; using System; using System.Collections.Generic; using System.Linq; @@ -10,17 +8,40 @@ namespace SiMay.Net.SessionProvider { public abstract class SessionProvider { - protected OnSessionNotify _onSessionNotifyProc; + public event Action SessionNotifyEventHandler; - protected SessionProvider(OnSessionNotify onSessionNotifyProc) + protected void SessionNotify(SessionProviderContext providerContext, TcpSessionNotify type) { - _onSessionNotifyProc = onSessionNotifyProc; + SessionNotifyEventHandler?.Invoke(providerContext, type); } + /// + /// 启动 + /// public abstract void StartSerivce(); + + /// + /// 广播发送 + /// + /// public abstract void BroadcastAsync(byte[] data); + + /// + /// 广播发送 + /// + /// + /// + /// public abstract void BroadcastAsync(byte[] data, int offset, int lenght); + + /// + /// 关闭所有 + /// public abstract void DisconnectAll(); + + /// + /// 关闭 + /// public abstract void CloseService(); } } \ No newline at end of file diff --git a/SiMay.Net.SessionProvider/Providers/TcpProxySessionProvider.cs b/SiMay.Net.SessionProvider/Providers/TcpProxySessionProvider.cs new file mode 100644 index 0000000..b6f1ab8 --- /dev/null +++ b/SiMay.Net.SessionProvider/Providers/TcpProxySessionProvider.cs @@ -0,0 +1,270 @@ +using System; +using System.Linq; +using System.Text; +using System.Threading; +using System.Threading.Tasks; +using System.Collections.Generic; +using System.Runtime.InteropServices; +using SiMay.Basic; +using SiMay.Core.Packets; +using SiMay.Sockets.Tcp; +using SiMay.Sockets.Tcp.Client; +using SiMay.Sockets.Tcp.Session; +using SiMay.Net.SessionProvider.Core; +using SiMay.Sockets.Tcp.TcpConfiguration; + +namespace SiMay.Net.SessionProvider.Providers +{ + public class TcpProxySessionProvider : SessionProvider + { + public event Action ProxyProviderNotify; + + private TcpProxyMainConnectionContext TcpProxyMainConnectionContext { get; set; } + + private const Int16 CHANNEL_LOGOUT = 0; + private const Int16 CHANNEL_LOGIN = 1; + + private int _currentState = 0; + private bool _wetherLogOut; + private IDictionary _proxySessions = new Dictionary(); + private TcpSocketSaeaClientAgent _clientAgent; + + /// + /// session代理提供器构造函数 + /// + /// 代理配置设置 + /// session事件通知 + /// 代理事件通知 + internal TcpProxySessionProvider(SessionProviderOptions options) + { + ApplicationConfiguartion.SetOptions(options); + + var clientConfig = new TcpSocketSaeaClientConfiguration(); + clientConfig.ReuseAddress = true; + clientConfig.KeepAlive = true; + clientConfig.KeepAliveInterval = 5000; + clientConfig.KeepAliveSpanTime = 1000; + + //不启用压缩 + clientConfig.CompressTransferFromPacket = false; + //停用应用心跳检测线程 + clientConfig.AppKeepAlive = false; + + _clientAgent = TcpSocketsFactory.CreateClientAgent(TcpSocketSaeaSessionType.Packet, clientConfig, (notify, session) => + { + switch (notify) + { + case TcpSessionNotify.OnConnected: + this.ConnectedHandler(session); + break; + case TcpSessionNotify.OnSend: + this.OnSend(session); + break; + case TcpSessionNotify.OnDataReceived: + this.OnMessageHandler(session); + break; + case TcpSessionNotify.OnClosed: + this.OnClosed(session); + break; + default: + break; + } + }); + } + private void SendACK(TcpSocketSaeaSession session, ConnectionWorkType type) + { + var ackBody = MessageHelper.CopyMessageHeadTo(SiMay.Core.MessageHead.C_GLOBAL_CONNECT, + new AckPack() + { + Type = (byte)type, + AccessId = ApplicationConfiguartion.Options.AccessId, + AccessKey = type == ConnectionWorkType.MainApplicationConnection ? ApplicationConfiguartion.Options.MainAppAccessKey : ApplicationConfiguartion.Options.AccessKey + }); + + var dataBuilder = new List(); + dataBuilder.AddRange(BitConverter.GetBytes(ApplicationConfiguartion.Options.AccessId)); + dataBuilder.AddRange(GZipHelper.Compress(ackBody, 0, ackBody.Length)); + session.SendAsync(dataBuilder.ToArray());//构造发送 + dataBuilder.Clear(); + } + + private void ConnectedHandler(TcpSocketSaeaSession session) + { + if (Interlocked.Exchange(ref _currentState, CHANNEL_LOGIN) == CHANNEL_LOGOUT) + { + this.TcpProxyMainConnectionContext = new TcpProxyMainConnectionContext(session); + this.TcpProxyMainConnectionContext.SessionNotifyEventHandler += ProxyMainConnectionSessionNotify; + this.TcpProxyMainConnectionContext.LogOutEventHandler += LogOutEventHandler; + this.TcpProxyMainConnectionContext.LaunchApplicationConnectEventHandler += LaunchApplicationConnectEventHandler; + this.TcpProxyMainConnectionContext.AccessIdOrKeyWrongEventHandler += AccessIdOrKeyWrongEventHandler; + session.AppTokens = new object[] { + this.TcpProxyMainConnectionContext, + ConnectionWorkType.MainApplicationConnection + }; + this.SendACK(session, ConnectionWorkType.MainApplicationConnection); + this.TcpProxyMainConnectionContext.PullSession(); + } + else + { + var tcpSessionContext = new TcpSocketSessionContext(session); + this._proxySessions.Add(tcpSessionContext.GetHashCode(), tcpSessionContext); + + session.AppTokens = new object[] { + tcpSessionContext, + ConnectionWorkType.ApplicationConnection + }; + this.SendACK(session, ConnectionWorkType.ApplicationConnection); + this.SessionNotify(tcpSessionContext, TcpSessionNotify.OnConnected); + } + } + + private void AccessIdOrKeyWrongEventHandler(TcpProxyMainConnectionContext mainConnectionContext) + => this.ProxyProviderNotify?.Invoke(Net.SessionProvider.ProxyProviderNotify.AccessIdOrKeyWrong, EventArgs.Empty); + + private void LaunchApplicationConnectEventHandler(TcpProxyMainConnectionContext mainConnectionContext) + => this._clientAgent.ConnectToServer(ApplicationConfiguartion.Options.ServiceIPEndPoint); + + private void LogOutEventHandler(TcpProxyMainConnectionContext mainConnectionContext, string message) + { + _wetherLogOut = true; + this.ProxyProviderNotify?.Invoke(Net.SessionProvider.ProxyProviderNotify.LogOut, new LogOutEventArgs(message)); + } + + private void ProxyMainConnectionSessionNotify(TcpProxyApplicationConnectionContext proxyContext, TcpSessionNotify type) + { + switch (type) + { + case TcpSessionNotify.OnConnected: + this.SessionNotify(proxyContext, TcpSessionNotify.OnConnected); + break; + case TcpSessionNotify.OnSend: + this.SessionNotify(proxyContext, TcpSessionNotify.OnSend); + break; + case TcpSessionNotify.OnDataReceiveing: + this.SessionNotify(proxyContext, TcpSessionNotify.OnDataReceiveing); + break; + case TcpSessionNotify.OnDataReceived: + this.SessionNotify(proxyContext, TcpSessionNotify.OnDataReceived); + break; + case TcpSessionNotify.OnClosed: + this.SessionNotify(proxyContext, TcpSessionNotify.OnClosed); + break; + } + } + + private void OnSend(TcpSocketSaeaSession session) + { + if (session.AppTokens.IsNull()) + return; + + var type = session.AppTokens[SysContanct.INDEX_WORKTYPE].ConvertTo(); + if (type == ConnectionWorkType.ApplicationConnection) + { + var tcpSessionContext = session.AppTokens[SysContanct.INDEX_WORKER].ConvertTo(); + this.SessionNotify(tcpSessionContext, TcpSessionNotify.OnSend); + } + } + + private void OnMessageHandler(TcpSocketSaeaSession session) + { + var type = session.AppTokens[SysContanct.INDEX_WORKTYPE].ConvertTo(); + if (type == ConnectionWorkType.MainApplicationConnection) + { + var sessionContext = session.AppTokens[SysContanct.INDEX_WORKER].ConvertTo(); + sessionContext.OnMessage(session.CompletedBuffer); + } + else if (type == ConnectionWorkType.ApplicationConnection) + { + var sessionContext = session.AppTokens[SysContanct.INDEX_WORKER].ConvertTo(); + this.SessionNotify(sessionContext, TcpSessionNotify.OnDataReceived); + } + } + + private void OnClosed(TcpSocketSaeaSession session) + { + if (session.AppTokens.IsNull() && this._currentState == CHANNEL_LOGOUT) + { + session.AppTokens = new object[] { + null, + ConnectionWorkType.MainApplicationConnection + }; + } + else if (session.AppTokens.IsNull() && this._currentState == CHANNEL_LOGIN) + { + return; + } + + var type = session.AppTokens[SysContanct.INDEX_WORKTYPE].ConvertTo(); + if (type == ConnectionWorkType.MainApplicationConnection) + { + if (!TcpProxyMainConnectionContext.IsNull()) + { + this.TcpProxyMainConnectionContext.CloseCurrentSession(); + this.TcpProxyMainConnectionContext.LaunchApplicationConnectEventHandler -= LaunchApplicationConnectEventHandler; + this.TcpProxyMainConnectionContext.AccessIdOrKeyWrongEventHandler -= AccessIdOrKeyWrongEventHandler; + this.TcpProxyMainConnectionContext.SessionNotifyEventHandler -= ProxyMainConnectionSessionNotify; + this.TcpProxyMainConnectionContext.LogOutEventHandler -= LogOutEventHandler; + } + this.TcpProxyMainConnectionContext = null; _currentState = CHANNEL_LOGOUT; + + lock (this) + { + foreach (var proxySession in _proxySessions.Select(c => c.Value)) + this.SessionNotify(proxySession, TcpSessionNotify.OnClosed); + this._proxySessions.Clear(); + } + + if (!_wetherLogOut) + { + var timer = new System.Timers.Timer(); + timer.Interval = 5000; + timer.Elapsed += (s, e) => + { + this._clientAgent.ConnectToServer(ApplicationConfiguartion.Options.ServiceIPEndPoint); + + timer.Stop(); + timer.Dispose(); + }; + timer.Start(); + } + } + else if (type == ConnectionWorkType.ApplicationConnection) + { + lock (this) + { + var sessionContext = session.AppTokens[SysContanct.INDEX_WORKER].ConvertTo(); + this.SessionNotify(sessionContext, TcpSessionNotify.OnClosed); + this._proxySessions.Remove(sessionContext.GetHashCode()); + } + } + } + + public override void StartSerivce() + { + this._clientAgent.ConnectToServer(ApplicationConfiguartion.Options.ServiceIPEndPoint); + } + public override void BroadcastAsync(byte[] data) + { + foreach (var session in this._proxySessions.Select(c => c.Value)) + session.SendAsync(data); + } + + public override void BroadcastAsync(byte[] data, int offset, int lenght) + { + foreach (var session in this._proxySessions.Select(c => c.Value)) + session.SendAsync(data, offset, lenght); + } + + public override void CloseService() + { + this._wetherLogOut = true; + + } + + public override void DisconnectAll() + { + foreach (var session in this._proxySessions.Select(c => c.Value)) + session.SessionClose(); + } + } +} diff --git a/SiMay.Net.SessionProvider/Providers/TcpProxySessionProviderHandle.cs b/SiMay.Net.SessionProvider/Providers/TcpProxySessionProviderHandle.cs deleted file mode 100644 index ff5bc44..0000000 --- a/SiMay.Net.SessionProvider/Providers/TcpProxySessionProviderHandle.cs +++ /dev/null @@ -1,456 +0,0 @@ -using SiMay.Net.SessionProvider.Delegate; -using SiMay.Net.SessionProvider.SessionBased; -using SiMay.Sockets.Tcp; -using SiMay.Sockets.Tcp.Client; -using SiMay.Sockets.Tcp.Server; -using System.Net; -using System; -using System.Collections.Generic; -using System.Linq; -using System.Text; -using System.Threading.Tasks; -using System.Threading; -using SiMay.Net.SessionProvider.Core; -using System.Runtime.InteropServices; -using SiMay.Net.SessionProvider.Notify; -using SiMay.Basic; -using SiMay.Sockets.Tcp.Session; -using SiMay.Sockets.Tcp.TcpConfiguration; -using SiMay.Core.Packets; -using SiMay.Core.Enums; -using static SiMay.Serialize.Standard.PacketSerializeHelper; - -namespace SiMay.Net.SessionProvider.Providers -{ - /// - /// 代理协议写的有些冗余。。有空抽出时间重构 - /// - public class TcpProxySessionProviderHandle : SessionProvider - { - private const Int16 AckHead = 1000; - private const Int16 CHANNEL_LOGOUT = 0; - private const Int16 CHANNEL_LOGIN = 1; - - bool _LogOut = false; - int _managerLoginSign = 0; - private OnProxyNotify _onProxyNotify; - private List _dataBuffer = new List(); - private List _tcpProxySessionList = new List(); - private TcpSocketSaeaClientAgent _clientAgent; - private SessionProviderOptions _options; - private TcpSocketSaeaSession _managerSession; - - /// - /// session代理提供器构造函数 - /// - /// 代理配置设置 - /// session事件通知 - /// 代理事件通知 - internal TcpProxySessionProviderHandle( - SessionProviderOptions options, - OnSessionNotify onSessionNotifyProc, - OnProxyNotify onProxyNotify) - : base(onSessionNotifyProc) - { - _options = options; - _onProxyNotify = onProxyNotify; - - var clientConfig = new TcpSocketSaeaClientConfiguration(); - clientConfig.ReuseAddress = true; - clientConfig.KeepAlive = true; - clientConfig.KeepAliveInterval = 5000; - clientConfig.KeepAliveSpanTime = 1000; - - _clientAgent = TcpSocketsFactory.CreateClientAgent(TcpSocketSaeaSessionType.Full, clientConfig, (notify, session) => - { - - switch (notify) - { - case TcpSocketCompletionNotify.OnConnected: - this.ConnectedHandler(session); - break; - case TcpSocketCompletionNotify.OnSend: - this.OnSend(session); - break; - case TcpSocketCompletionNotify.OnDataReceiveing: - this.PacketHandler(session); - break; - case TcpSocketCompletionNotify.OnClosed: - this.OnClosed(session); - break; - default: - break; - } - }); - } - - private void ConnectedHandler(TcpSocketSaeaSession session) - { - if (Interlocked.Exchange(ref _managerLoginSign, CHANNEL_LOGIN) == CHANNEL_LOGOUT) - { - //表示代理管理连接登陆 - this.SendAck(session, SessionWorkType.ManagerSession); - - _managerSession = session; - session.AppTokens = new object[] - { - SessionWorkType.ManagerSession, - null - }; - - //获取所有主连接 - MessageHelper.SendMessage(session, MessageHead.Msg_Pull_Session); - } - else - { - this.SendAck(session, SessionWorkType.ManagerWorkSession); - var sessionBased = new TcpProxySessionBased(session); - session.AppTokens = new object[] - { - SessionWorkType.ManagerWorkSession, - sessionBased - }; - - this._onSessionNotifyProc(SessionCompletedNotify.OnConnected, sessionBased as SessionProviderContext); - } - } - private void OnSend(TcpSocketSaeaSession session) - { - if ((SessionWorkType)session.AppTokens[0] == SessionWorkType.ManagerWorkSession) - { - var sessionBased = session.AppTokens[1] as TcpProxySessionBased; - sessionBased._sendTransferredBytes = session.SendTransferredBytes; - this._onSessionNotifyProc(SessionCompletedNotify.OnSend, sessionBased as SessionProviderContext); - } - } - - private void PacketHandler(TcpSocketSaeaSession session) - { - byte[] data = new byte[session.ReceiveBytesTransferred]; - Array.Copy(session.CompletedBuffer, 0, data, 0, data.Length); - - if ((SessionWorkType)session.AppTokens[0] == SessionWorkType.ManagerSession) - { - _dataBuffer.AddRange(data); - do - { - if (_dataBuffer.Count < 4) - return; - - byte[] lenBytes = _dataBuffer.GetRange(0, 4).ToArray(); - int packageLen = BitConverter.ToInt32(lenBytes, 0); - - //缓冲区越界判断 - if (packageLen > (1024 * 1024 * 2) || packageLen < 1) - { - this.ConsoleWriteLine("DEBUG BUFFER OutOfRange !! PacketProcess MAIN", ConsoleColor.Red); - this._dataBuffer.Clear(); - session.Close(true); - return; - } - - if (packageLen > _dataBuffer.Count - 4) - return; - - byte[] completedBytes = _dataBuffer.GetRange(4, packageLen).ToArray(); - - this.OnMessage(completedBytes); - - _dataBuffer.RemoveRange(0, packageLen + 4); - - } while (_dataBuffer.Count > 4); - } - else - { - var sessionBased = session.AppTokens[1] as TcpProxySessionBased; - - sessionBased._receiveTransferredBytes = data.Length; - - this._onSessionNotifyProc(SessionCompletedNotify.OnRecv, sessionBased as SessionProviderContext); - - sessionBased.Buffer.AddRange(data); - do - { - if (sessionBased.Buffer.Count < 4) - return; - - byte[] lenBytes = sessionBased.Buffer.GetRange(0, 4).ToArray(); - int packageLen = BitConverter.ToInt32(lenBytes, 0); - - //缓冲区越界判断 - if (packageLen > (1024 * 1024 * 2) || packageLen < 1) - { - this.ConsoleWriteLine("DEBUG BUFFER OutOfRange !! PacketProcess WORK", ConsoleColor.Red); - session.Close(true); - return; - } - - if (packageLen > sessionBased.Buffer.Count - 4) - return; - - byte[] completeBytes = sessionBased.Buffer.GetRange(4, packageLen).ToArray(); - - sessionBased._completedBuffer = GZipHelper.Decompress(completeBytes); - - this._onSessionNotifyProc(SessionCompletedNotify.OnReceived, sessionBased as SessionProviderContext); - - sessionBased.Buffer.RemoveRange(0, packageLen + 4); - - } while (sessionBased.Buffer.Count > 4); - } - } - - private void OnClosed(TcpSocketSaeaSession session) - { - if (session.AppTokens == null && this._managerLoginSign == 0) - { - session.AppTokens = new object[] - { - SessionWorkType.ManagerSession, - null - }; - } - else if (this._managerLoginSign == 1 && session.AppTokens == null) - { - return; - } - - if ((SessionWorkType)session.AppTokens[0] == SessionWorkType.ManagerSession) - { - Interlocked.Exchange(ref this._managerLoginSign, 0); - - //_manager_buffer.Clear(); - _managerSession = null; - - foreach (var _session in this._tcpProxySessionList) - { - this._onSessionNotifyProc(SessionCompletedNotify.OnClosed, _session as SessionProviderContext); - _session.Dispose(); - } - this._tcpProxySessionList.Clear(); - - if (!this._LogOut) - { - this.ConsoleWriteLine("DEBUG ACCEPT CONNECT", ConsoleColor.Green); - var timer = new System.Timers.Timer(); - timer.Interval = 5000; - timer.Elapsed += (s, e) => - { - this.ConsoleWriteLine("DEBUG RE CONNECT", ConsoleColor.Green); - this._clientAgent.ConnectToServer(this._options.ServiceIPEndPoint); - - timer.Stop(); - timer.Dispose(); - }; - timer.Start(); - } - - - } - else - { - var sessionBased = session.AppTokens[1] as TcpProxySessionBased; - this._onSessionNotifyProc(SessionCompletedNotify.OnClosed, sessionBased as SessionProviderContext); - sessionBased.Dispose(); - } - } - private void OnMessage(byte[] data) - { - MessageHead cmd = (MessageHead)data[0]; - switch (cmd) - { - case MessageHead.Msg_Set_Session: - this.CreateSession(data); - break; - case MessageHead.Msg_Connect_Work: - this._clientAgent.ConnectToServer(this._options.ServiceIPEndPoint); - break; - case MessageHead.Msg_LogOut: - this.LogOut(); - break; - case MessageHead.Msg_MessageData: - this.ProcessPackage(data); - break; - case MessageHead.Msg_Close_Session: - this.ProcessSessionClose(data); - break; - case MessageHead.Msg_AccessKeyWrong: - this.ProcessAccessKeyWrong(); - break; - } - - - } - private void ProcessAccessKeyWrong() - { - this._LogOut = true; - if (this._managerLoginSign == 1) - this._managerSession.Close(true); - - this._onProxyNotify?.Invoke(ProxyNotify.AccessKeyWrong); - } - private void ProcessPackage(byte[] data) - { - long id = BitConverter.ToInt64(data, 1); - GCHandle gc = GCHandle.FromIntPtr(new IntPtr(id)); - TcpProxySessionBased session = gc.Target as TcpProxySessionBased; - - if (session == null) - { - this.ConsoleWriteLine("DEBUG ProcessPackage SESSION NULL", ConsoleColor.Red); - return; - } - - byte[] bytes = new byte[data.Length - (sizeof(Int64) + 1)]; - Array.Copy(data, sizeof(Int64) + 1, bytes, 0, bytes.Length); - - session._receiveTransferredBytes = bytes.Length; - this._onSessionNotifyProc(SessionCompletedNotify.OnRecv, session as SessionProviderContext); - session.Buffer.AddRange(bytes); - do - { - if (session.Buffer.Count < 4) - return; - - byte[] lenBytes = session.Buffer.GetRange(0, 4).ToArray(); - int packageLen = BitConverter.ToInt32(lenBytes, 0); - - //缓冲区越界判断 - if (packageLen > (1024 * 1024 * 2) || packageLen < 1) - { - this.ConsoleWriteLine("DEBUG BUFFER OutOfRange !! ProcessPackage DATA", ConsoleColor.Red); - this._managerSession.Close(true); - return; - } - - if (packageLen > session.Buffer.Count - 4) - return; - - byte[] completeBytes = session.Buffer.GetRange(4, packageLen).ToArray(); - - session._completedBuffer = GZipHelper.Decompress(completeBytes); - - this._onSessionNotifyProc(SessionCompletedNotify.OnReceived, session as SessionProviderContext); - - session.Buffer.RemoveRange(0, packageLen + 4); - - } while (session.Buffer.Count > 4); - } - - - private void LogOut() - { - this._LogOut = true; - if (this._managerLoginSign == 1) - this._managerSession.Close(true); - - this._onProxyNotify?.Invoke(ProxyNotify.LogOut); - } - - private void ProcessSessionClose(byte[] data) - { - long id = BitConverter.ToInt64(data, 1); - GCHandle gc = GCHandle.FromIntPtr(new IntPtr(id)); - - TcpProxySessionBased session = gc.Target as TcpProxySessionBased; - this._onSessionNotifyProc(SessionCompletedNotify.OnClosed, session as SessionProviderContext); - this._tcpProxySessionList.Remove(session);//移除List引用 - session.Buffer.Clear(); - session.Dispose(); - //////////////////////////////check - } - private void CreateSession(byte[] data) - { - byte[] body = new byte[data.Length - 1]; - Array.Copy(data, 1, body, 0, body.Length); - - //byte[] sessionIds = new byte[body.Length * 2]; - List buffer = new List(); - - byte[] sessionId = new byte[sizeof(Int64) * 2]; - - List sessionList = new List(); - for (int i = 0; i < body.Length / sizeof(Int64); i++) - { - Array.Copy(body, i * sizeof(Int64), sessionId, 0, sizeof(Int64)); - TcpProxySessionBased sessionBased = new TcpProxySessionBased(_managerSession); - sessionBased.RemoteId = BitConverter.ToInt64(sessionId, 0); - - Console.WriteLine("CreateSession:" + sessionBased.RemoteId + " Id:" + sessionBased.Id); - - sessionList.Add(sessionBased); - - BitConverter.GetBytes(sessionBased.Id).CopyTo(sessionId, sizeof(Int64)); - buffer.AddRange(sessionId); - //Array.Copy(sessionId, 0, sessionIds, i * (sizeof(Int64) + sizeof(Int64)), sizeof(Int64) + sizeof(Int64)); - } - - MessageHelper.SendMessage(_managerSession, MessageHead.Msg_Set_Session_Id, buffer.ToArray()); - - this._tcpProxySessionList.AddRange(sessionList.ToArray()); - - foreach (var session in sessionList) - { - this._onSessionNotifyProc?.Invoke(SessionCompletedNotify.OnConnected, session as SessionProviderContext); - } - - sessionList.Clear(); - } - - private void SendAck(TcpSocketSaeaSession session, SessionWorkType type) - { - var typeByte = (byte)type; - var ackBody = SerializePacket(new AckPack() - { - Type = typeByte.ConvertTo(), - AccessId = _options.AccessId, - AccessKey = _options.AccessKey - }); - ackBody = GZipHelper.Compress(ackBody, 0, ackBody.Length); - - var dataBuilder = new List(); - dataBuilder.AddRange(BitConverter.GetBytes(ackBody.Length)); - dataBuilder.AddRange(ackBody); - ackBody = dataBuilder.ToArray(); - dataBuilder.Clear(); - session.SendAsync(ackBody);//构造发送 - } - - private void ConsoleWriteLine(string log, ConsoleColor color) - { - Console.ForegroundColor = color; - Console.WriteLine(log); - Console.ResetColor(); - } - - public override void StartSerivce() - { - this._LogOut = false; - this._clientAgent.ConnectToServer(this._options.ServiceIPEndPoint); - } - public override void BroadcastAsync(byte[] data) - { - foreach (var session in this._tcpProxySessionList) - session.SendAsync(data); - } - - public override void BroadcastAsync(byte[] data, int offset, int lenght) - { - foreach (var session in this._tcpProxySessionList) - session.SendAsync(data, offset, lenght); - } - - public override void CloseService() - { - this._LogOut = true; - if (this._managerLoginSign == 1) - _managerSession.Close(true); - } - - public override void DisconnectAll() - { - foreach (var session in this._tcpProxySessionList) - session.SessionClose(); - } - } -} diff --git a/SiMay.Net.SessionProvider/Providers/TcpSocketSessionProviderHandle.cs b/SiMay.Net.SessionProvider/Providers/TcpSocketSessionProvider.cs similarity index 32% rename from SiMay.Net.SessionProvider/Providers/TcpSocketSessionProviderHandle.cs rename to SiMay.Net.SessionProvider/Providers/TcpSocketSessionProvider.cs index c8c12fe..ae2ad30 100644 --- a/SiMay.Net.SessionProvider/Providers/TcpSocketSessionProviderHandle.cs +++ b/SiMay.Net.SessionProvider/Providers/TcpSocketSessionProvider.cs @@ -1,62 +1,50 @@ -using SiMay.Net.SessionProvider.Delegate; -using SiMay.Net.SessionProvider.Notify; -using SiMay.Net.SessionProvider.SessionBased; -using SiMay.Sockets.Tcp; -using SiMay.Sockets.Tcp.Server; -using SiMay.Sockets.Tcp.TcpConfiguration; -using System; -using System.Collections.Generic; +using System; using System.Linq; using System.Text; using System.Threading.Tasks; +using SiMay.Basic; +using SiMay.Sockets.Tcp; +using SiMay.Sockets.Tcp.Server; +using SiMay.Sockets.Tcp.TcpConfiguration; namespace SiMay.Net.SessionProvider.Providers { - public class TcpSocketSessionProviderHandle : SessionProvider + public class TcpSocketSessionProvider : SessionProvider { TcpSocketSaeaServer _server; - SessionProviderOptions _options; - internal TcpSocketSessionProviderHandle( - SessionProviderOptions options, - OnSessionNotify onSessionNotifyProc) - : base(onSessionNotifyProc) + internal TcpSocketSessionProvider(SessionProviderOptions options) { - - _options = options; - + ApplicationConfiguartion.SetOptions(options); + ; var serverConfig = new TcpSocketSaeaServerConfiguration(); serverConfig.AppKeepAlive = true; serverConfig.CompressTransferFromPacket = false; - serverConfig.PendingConnectionBacklog = options.PendingConnectionBacklog; + serverConfig.PendingConnectionBacklog = ApplicationConfiguartion.Options.PendingConnectionBacklog; _server = TcpSocketsFactory.CreateServerAgent(TcpSocketSaeaSessionType.Packet, serverConfig, (notify, session) => { switch (notify) { - case TcpSocketCompletionNotify.OnConnected: - - var sessionBased = new TcpSocketSessionBased(session); + case TcpSessionNotify.OnConnected: - session.AppTokens = new object[] - { + SessionProviderContext sessionBased = new TcpSocketSessionContext(session); + session.AppTokens = new object[] { sessionBased }; - - _onSessionNotifyProc(SessionCompletedNotify.OnConnected, sessionBased); - + this.SessionNotify(sessionBased, TcpSessionNotify.OnConnected); break; - case TcpSocketCompletionNotify.OnSend: - _onSessionNotifyProc(SessionCompletedNotify.OnSend, session.AppTokens[0] as SessionProviderContext); + case TcpSessionNotify.OnSend: + this.SessionNotify(session.AppTokens.First().ConvertTo(), TcpSessionNotify.OnSend); break; - case TcpSocketCompletionNotify.OnDataReceiveing: - _onSessionNotifyProc(SessionCompletedNotify.OnRecv, session.AppTokens[0] as SessionProviderContext); + case TcpSessionNotify.OnDataReceiveing: + this.SessionNotify(session.AppTokens.First().ConvertTo(), TcpSessionNotify.OnDataReceiveing); break; - case TcpSocketCompletionNotify.OnDataReceived: - _onSessionNotifyProc(SessionCompletedNotify.OnReceived, session.AppTokens[0] as SessionProviderContext); + case TcpSessionNotify.OnDataReceived: + this.SessionNotify(session.AppTokens.First().ConvertTo(), TcpSessionNotify.OnDataReceived); break; - case TcpSocketCompletionNotify.OnClosed: - _onSessionNotifyProc(SessionCompletedNotify.OnClosed, session.AppTokens[0] as SessionProviderContext); + case TcpSessionNotify.OnClosed: + this.SessionNotify(session.AppTokens.First().ConvertTo(), TcpSessionNotify.OnClosed); break; default: break; @@ -64,18 +52,17 @@ namespace SiMay.Net.SessionProvider.Providers }); } - public override void StartSerivce() => - _server.Listen(_options.ServiceIPEndPoint); - public override void BroadcastAsync(byte[] data) => - _server.BroadcastAsync(data); + public override void StartSerivce() + { + _server.Listen(ApplicationConfiguartion.Options.ServiceIPEndPoint); + } + + public override void BroadcastAsync(byte[] data) => _server.BroadcastAsync(data); - public override void BroadcastAsync(byte[] data, int offset, int lenght) => - _server.BroadcastAsync(data, offset, lenght); + public override void BroadcastAsync(byte[] data, int offset, int lenght) => _server.BroadcastAsync(data, offset, lenght); - public override void CloseService() => - _server.Dispose(); + public override void CloseService() => _server.Dispose(); - public override void DisconnectAll() => - _server.DisconnectAll(true); + public override void DisconnectAll() => _server.DisconnectAll(true); } } diff --git a/SiMay.Net.SessionProvider/SessionBased/TcpProxySessionBased.cs b/SiMay.Net.SessionProvider/SessionBased/TcpProxySessionBased.cs deleted file mode 100644 index 377eb2c..0000000 --- a/SiMay.Net.SessionProvider/SessionBased/TcpProxySessionBased.cs +++ /dev/null @@ -1,108 +0,0 @@ -using SiMay.Basic; -using SiMay.Net.SessionProvider.Core; -using SiMay.Sockets.Tcp; -using SiMay.Sockets.Tcp.Session; -using System; -using System.Collections.Generic; -using System.Linq; -using System.Runtime.InteropServices; -using System.Text; -using System.Threading; - -namespace SiMay.Net.SessionProvider.SessionBased -{ - public class TcpProxySessionBased : SessionProviderContext, IDisposable - { - long _id; - internal long Id { get { return _id; } } - - internal long RemoteId { get; set; } - internal List Buffer = new List(); - - TcpSocketSaeaSession _session; - int _disposable = 0; - public TcpProxySessionBased(TcpSocketSaeaSession session) - { - Socket = session.Socket; - _session = session; - - GCHandle gc = GCHandle.Alloc(this, GCHandleType.WeakTrackResurrection); - this._id = GCHandle.ToIntPtr(gc).ToInt64(); - } - - internal int _sendTransferredBytes; - public override int SendTransferredBytes - { - get { return this._sendTransferredBytes; } - } - - internal int _receiveTransferredBytes; - public override int ReceiveTransferredBytes - { - get { return this._receiveTransferredBytes; } - } - - internal byte[] _completedBuffer; - public override byte[] CompletedBuffer - { - get { return _completedBuffer; } - } - - public override void SendAsync(byte[] data) - { - this.SendAsync(data, 0, data.Length); - } - - public override void SendAsync(byte[] data, int offset, int length) - { - if (this._disposable == 1) - return; - - byte[] bytes = GZipHelper.Compress(data, offset, length); - if ((SessionWorkType)_session.AppTokens[0] == SessionWorkType.ManagerSession) - { - byte[] body = new byte[sizeof(Int64) + sizeof(Int32) + bytes.Length]; - BitConverter.GetBytes(this.RemoteId).CopyTo(body, 0); - BitConverter.GetBytes(bytes.Length).CopyTo(body, 8); - bytes.CopyTo(body, 12); - - MessageHelper.SendMessage(_session, MessageHead.Msg_MessageData, body); - } - else - { - byte[] body = new byte[bytes.Length + sizeof(Int32)]; - BitConverter.GetBytes(bytes.Length).CopyTo(body, 0); - bytes.CopyTo(body, 4); - - _session.SendAsync(body, 0, body.Length); - } - } - - public override void SessionClose() - { - if (this._disposable == 1) - return; - - if ((SessionWorkType)_session.AppTokens[0] == SessionWorkType.ManagerSession) - { - MessageHelper.SendMessage(_session, MessageHead.Msg_Close_Session, BitConverter.GetBytes(this.RemoteId)); - } - else - { - _session.Close(true); - } - } - - public void Dispose() - { - if (Interlocked.Exchange(ref this._disposable, 1) == 0) - { - //this.Buffer.Clear(); - //this.AppTokens = null; - - GCHandle gc = GCHandle.FromIntPtr(new IntPtr(this.Id)); - gc.Free(); - } - } - } -} diff --git a/SiMay.Net.SessionProvider/SessionBased/TcpSocketSessionBased.cs b/SiMay.Net.SessionProvider/SessionBased/TcpSocketSessionBased.cs deleted file mode 100644 index 65b53ff..0000000 --- a/SiMay.Net.SessionProvider/SessionBased/TcpSocketSessionBased.cs +++ /dev/null @@ -1,50 +0,0 @@ -using SiMay.Sockets.Tcp; -using SiMay.Sockets.Tcp.Session; -using System; -using System.Collections.Generic; -using System.Linq; -using System.Text; - -namespace SiMay.Net.SessionProvider.SessionBased -{ - public class TcpSocketSessionBased : SessionProviderContext - { - TcpSocketSaeaSession _session; - internal TcpSocketSessionBased(TcpSocketSaeaSession session) - { - Socket = session.Socket; - _session = session; - } - - public override int SendTransferredBytes - { - get - { - return _session.SendTransferredBytes; - } - } - public override int ReceiveTransferredBytes - { - get - { - return _session.ReceiveBytesTransferred; - } - } - public override byte[] CompletedBuffer - { - get - { - return _session.CompletedBuffer; - } - } - - public override void SendAsync(byte[] data) - => _session.SendAsync(data); - - public override void SendAsync(byte[] data, int offset, int length) - => _session.SendAsync(data, offset, length); - - public override void SessionClose() - => _session.Close(true); - } -} diff --git a/SiMay.Net.SessionProvider/SessionProviderFactory.cs b/SiMay.Net.SessionProvider/SessionProviderFactory.cs index b1b3235..0733c21 100644 --- a/SiMay.Net.SessionProvider/SessionProviderFactory.cs +++ b/SiMay.Net.SessionProvider/SessionProviderFactory.cs @@ -1,33 +1,23 @@ -using SiMay.Net.SessionProvider.Delegate; -using SiMay.Net.SessionProvider.Notify; -using SiMay.Net.SessionProvider.Providers; -using SiMay.Net.SessionProvider.SessionBased; -using System; +using System; using System.Collections.Generic; using System.Linq; using System.Text; using System.Threading.Tasks; +using SiMay.Net.SessionProvider.Providers; namespace SiMay.Net.SessionProvider { public class SessionProviderFactory { - public static SessionProvider CreateTcpSessionProvider(SessionProviderOptions options, - OnSessionNotify onSessionNotifyProc) + public static SessionProvider CreateTcpSessionProvider(SessionProviderOptions options) { - - SessionProvider provider = new TcpSocketSessionProviderHandle(options, onSessionNotifyProc); - + SessionProvider provider = new TcpSocketSessionProvider(options); return provider; } - public static SessionProvider CreateProxySessionProvider(SessionProviderOptions options, - OnSessionNotify onSessionNotifyProc, - OnProxyNotify onProxyNotifyProc) + public static SessionProvider CreateProxySessionProvider(SessionProviderOptions options) { - - SessionProvider provider = new TcpProxySessionProviderHandle(options, onSessionNotifyProc, onProxyNotifyProc); - + SessionProvider provider = new TcpProxySessionProvider(options); return provider; } diff --git a/SiMay.Net.SessionProvider/SessionProviderOptions.cs b/SiMay.Net.SessionProvider/SessionProviderOptions.cs index a53fbe2..875ce30 100644 --- a/SiMay.Net.SessionProvider/SessionProviderOptions.cs +++ b/SiMay.Net.SessionProvider/SessionProviderOptions.cs @@ -7,28 +7,47 @@ using System.Threading.Tasks; namespace SiMay.Net.SessionProvider { + internal class ApplicationConfiguartion + { + public static void SetOptions(SessionProviderOptions options) => Options = options; + public static SessionProviderOptions Options { get; private set; } + } + public class SessionProviderOptions { /// - /// Session提供类型 + /// 中间服务识别的唯一ID /// - public SessionProviderType SessionProviderType { get; set; } + public long AccessId { get; set; } /// - /// 中间服务识别的唯一ID + /// 主控端连接Key /// - public long AccessId { get; set; } + public long MainAppAccessKey { get; set; } /// /// 中间服务访问Key /// public long AccessKey { get; set; } + /// + /// 连接挂起队列 + /// + public int PendingConnectionBacklog { get; set; } + + /// + /// 最大包长度 + /// + public int MaxPacketSize { get; set; } + + /// + /// Session提供类型 + /// + public SessionProviderType SessionProviderType { get; set; } + /// /// 中间服务地址 /// public IPEndPoint ServiceIPEndPoint { get; set; } - - public int PendingConnectionBacklog { get; set; } } } diff --git a/SiMay.Net.SessionProvider/SessionWorkType.cs b/SiMay.Net.SessionProvider/SysContanct.cs similarity index 51% rename from SiMay.Net.SessionProvider/SessionWorkType.cs rename to SiMay.Net.SessionProvider/SysContanct.cs index 079fcf1..a8ff12d 100644 --- a/SiMay.Net.SessionProvider/SessionWorkType.cs +++ b/SiMay.Net.SessionProvider/SysContanct.cs @@ -1,13 +1,12 @@ using System; using System.Collections.Generic; -using System.Linq; using System.Text; namespace SiMay.Net.SessionProvider { - public enum SessionWorkType + public class SysContanct { - ManagerSession = 2, - ManagerWorkSession + public const int INDEX_WORKER = 0; + public const int INDEX_WORKTYPE = 1; } } diff --git a/SiMay.Net.SessionProvider/SessionBased/SessionProviderContext.cs b/SiMay.Net.SessionProvider/TcpSessionConnection/SessionProviderContext.cs similarity index 40% rename from SiMay.Net.SessionProvider/SessionBased/SessionProviderContext.cs rename to SiMay.Net.SessionProvider/TcpSessionConnection/SessionProviderContext.cs index 3097823..584d1ca 100644 --- a/SiMay.Net.SessionProvider/SessionBased/SessionProviderContext.cs +++ b/SiMay.Net.SessionProvider/TcpSessionConnection/SessionProviderContext.cs @@ -1,39 +1,54 @@ -using SiMay.Sockets.Tcp; -using System; -using System.Collections.Generic; +using System; +using System.Text; using System.Linq; using System.Net.Sockets; -using System.Text; +using System.Collections.Generic; +using SiMay.Sockets.Tcp.Session; +using SiMay.Net.SessionProvider.Core; -namespace SiMay.Net.SessionProvider.SessionBased +namespace SiMay.Net.SessionProvider { - public abstract class SessionProviderContext + public abstract class SessionProviderContext : IDisposable { /// - /// 当前Socket + /// 当前会话 /// - public Socket Socket { get; set; } + public TcpSocketSaeaSession CurrentSession { get; protected set; } /// /// 异步上下文对象 /// public object[] AppTokens { get; set; } - - public abstract int SendTransferredBytes { get;} + /// + /// 发送长度 + /// + public virtual int SendTransferredBytes { get; protected set; } - public abstract int ReceiveTransferredBytes { get;} + /// + /// 接受长度 + /// + public virtual int ReceiveTransferredBytes { get; protected set; } /// /// 完成缓冲区 /// - public abstract byte[] CompletedBuffer { get; } + public virtual byte[] CompletedBuffer { get; protected set; } + + /// + /// Socket选项设置 + /// + /// + /// + /// + public abstract void SetSocketOptions(SocketOptionLevel optionLevel, SocketOptionName optionName, object optionValue); /// /// 异步发送 /// /// - public abstract void SendAsync(byte[] data); + public virtual void SendAsync(byte[] data) + => SendAsync(data, 0, data.Length); /// /// 异步发送 @@ -47,5 +62,13 @@ namespace SiMay.Net.SessionProvider.SessionBased /// 关闭会话 /// public abstract void SessionClose(); + + /// + /// 释放资源 + /// + public virtual void Dispose() + { + CurrentSession = null; + } } } \ No newline at end of file diff --git a/SiMay.Net.SessionProvider/TcpSessionConnection/TcpProxyApplicationConnectionContext.cs b/SiMay.Net.SessionProvider/TcpSessionConnection/TcpProxyApplicationConnectionContext.cs new file mode 100644 index 0000000..370d4ec --- /dev/null +++ b/SiMay.Net.SessionProvider/TcpSessionConnection/TcpProxyApplicationConnectionContext.cs @@ -0,0 +1,109 @@ +using System; +using System.Text; +using System.Net.Sockets; +using System.Collections.Generic; +using SiMay.Basic; +using SiMay.Sockets.Tcp.Session; +using SiMay.Net.SessionProvider.Core; + +namespace SiMay.Net.SessionProvider +{ + public class TcpProxyApplicationConnectionContext : SessionProviderContext + { + /// + /// 消息接受完成 + /// + public event Action DataReceivedEventHandler; + + /// + /// 消息发送完成 + /// + public event Action DataSendEventHandler; + + /// + /// 标识 + /// + public long Id { get; private set; } + + /// + /// 缓冲区 + /// + public virtual List ListByteBuffer + { + get; + set; + } = new List(); + + /// + /// 设置当前会话 + /// + /// + public void SetSession(TcpSocketSaeaSession session, long id, byte[] ackData) + { + Id = id; + CurrentSession = session; + CompletedBuffer = ackData; + } + + /// + /// 消息处理 + /// + public void OnMessage(int receiveLength) + { + ReceiveTransferredBytes = receiveLength; + + int defineHeadSize = sizeof(int); + do + { + if (ListByteBuffer.Count < defineHeadSize) + return; + + byte[] lenBytes = ListByteBuffer.GetRange(0, defineHeadSize).ToArray(); + int packageLen = BitConverter.ToInt32(lenBytes, 0); + + if (packageLen < 0) + throw new Exception("Illegal length!"); + + if (packageLen + defineHeadSize > ListByteBuffer.Count) + return; + this.CompletedBuffer = ListByteBuffer.GetRange(defineHeadSize, packageLen).ToArray(); + this.DataReceivedEventHandler?.Invoke(this); + ListByteBuffer.RemoveRange(0, packageLen + defineHeadSize); + + } while (ListByteBuffer.Count > defineHeadSize); + } + + public override void SendAsync(byte[] data, int offset, int length) + { + var packetData = MessageHelper.CopyMessageHeadTo(MessageHead.APP_MESSAGE_DATA, + new MessageDataPacket() + { + AccessId = ApplicationConfiguartion.Options.AccessId, + DispatcherId = this.Id, + Data = data.Copy(offset, length) + }); + this.CurrentSession.SendAsync(packetData); + + this.SendTransferredBytes = packetData.Length; + this.DataSendEventHandler?.Invoke(this); + } + /// + /// 不支持关闭代理连接 + /// + public override void SessionClose() + { + throw new NotImplementedException("not support"); + } + + public override void SetSocketOptions(SocketOptionLevel optionLevel, SocketOptionName optionName, object optionValue) + { + throw new NotImplementedException("not support"); + } + + public override void Dispose() + { + ListByteBuffer.Clear(); + base.Dispose(); + } + } +} diff --git a/SiMay.Net.SessionProvider/TcpSessionConnection/TcpProxyMainConnectionContext.cs b/SiMay.Net.SessionProvider/TcpSessionConnection/TcpProxyMainConnectionContext.cs new file mode 100644 index 0000000..c61a3d1 --- /dev/null +++ b/SiMay.Net.SessionProvider/TcpSessionConnection/TcpProxyMainConnectionContext.cs @@ -0,0 +1,145 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Net.Sockets; +using System.Text; +using SiMay.Basic; +using SiMay.Net.SessionProvider.Core; +using SiMay.Net.SessionProvider.Providers; +using SiMay.Sockets.Tcp; +using SiMay.Sockets.Tcp.Session; + +namespace SiMay.Net.SessionProvider +{ + public class TcpProxyMainConnectionContext + { + /// + /// 代理会话通知 + /// + public event Action SessionNotifyEventHandler; + + /// + /// 登出 + /// + public event Action LogOutEventHandler; + + /// + /// Id或者Key错误 + /// + public event Action AccessIdOrKeyWrongEventHandler; + + /// + /// 发起一个应用连接 + /// + public event Action LaunchApplicationConnectEventHandler; + + private TcpSocketSaeaSession _currentSession; + private IDictionary _proxySessions = new Dictionary(); + + public TcpProxyMainConnectionContext(TcpSocketSaeaSession session) => _currentSession = session; + + public void OnMessage(byte[] data) + { + switch (data.GetMessageHead()) + { + case MessageHead.MID_SESSION: + this.CreateSession(data); + break; + case MessageHead.MID_SESSION_CLOSED: + this.SessionClosedHandler(data); + break; + case MessageHead.MID_APPWORK: + this.LaunchApplicationConnectEventHandler?.Invoke(this); + break; + case MessageHead.MID_MESSAGE_DATA: + this.SessionOnMessage(data); + break; + case MessageHead.MID_ACCESS_KEY_WRONG: + this.AccessIdOrKeyWrongEventHandler?.Invoke(this); + break; + case MessageHead.MID_LOGOUT: + this.LogOutHandler(data); + break; + default: + break; + } + } + + private void CreateSession(byte[] data) + { + var sessions = data.GetMessageEntity(); + foreach (var session in sessions.SessionItems) + { + if (!this._proxySessions.ContainsKey(session.Id)) + { + var proxyConnectionContext = new TcpProxyApplicationConnectionContext(); + proxyConnectionContext.DataReceivedEventHandler += DataReceivedEventHandler; + proxyConnectionContext.DataSendEventHandler += DataSendEventHandler; + proxyConnectionContext.SetSession(_currentSession, session.Id, session.ACKPacketData); + this._proxySessions.Add(session.Id, proxyConnectionContext); + this.SessionNotifyEventHandler?.Invoke(proxyConnectionContext, TcpSessionNotify.OnConnected); + this.SessionNotifyEventHandler?.Invoke(proxyConnectionContext, TcpSessionNotify.OnDataReceived); + } + } + } + + private void DataSendEventHandler(TcpProxyApplicationConnectionContext proxyConnectionContext) + => this.SessionNotifyEventHandler?.Invoke(proxyConnectionContext, TcpSessionNotify.OnSend); + + private void DataReceivedEventHandler(TcpProxyApplicationConnectionContext proxyConnectionContext) + => this.SessionNotifyEventHandler?.Invoke(proxyConnectionContext, TcpSessionNotify.OnDataReceived); + + private void SessionClosedHandler(byte[] data) + { + var closedPack = data.GetMessageEntity(); + if (_proxySessions.ContainsKey(closedPack.Id)) + { + var proxyConnectionContext = _proxySessions.GetValue(closedPack.Id).ConvertTo(); + proxyConnectionContext.DataReceivedEventHandler -= DataReceivedEventHandler; + proxyConnectionContext.DataSendEventHandler -= DataSendEventHandler; + this.SessionNotifyEventHandler?.Invoke(proxyConnectionContext, TcpSessionNotify.OnClosed); + _proxySessions.Remove(closedPack.Id); + proxyConnectionContext.Dispose(); + } + } + + private void SessionOnMessage(byte[] data) + { + var message = data.GetMessageEntity(); + if (_proxySessions.ContainsKey(message.DispatcherId)) + { + var proxyConnectionContext = _proxySessions.GetValue(message.DispatcherId).ConvertTo(); + proxyConnectionContext.ListByteBuffer.AddRange(message.Data); + proxyConnectionContext.OnMessage(message.Data.Length); + this.SessionNotifyEventHandler?.Invoke(proxyConnectionContext, TcpSessionNotify.OnDataReceiveing); + } + } + + private void LogOutHandler(byte[] data) + { + var logOut = data.GetMessageEntity(); + this.LogOutEventHandler?.Invoke(this, logOut.Message); + } + + /// + /// 获取Session + /// + public void PullSession() + { + var data = MessageHelper.CopyMessageHeadTo(MessageHead.APP_PULL_SESSION); + _currentSession.SendAsync(data); + } + + public void CloseCurrentSession() + { + foreach (TcpProxyApplicationConnectionContext proxyContext in _proxySessions.Select(c => c.Value)) + { + this.SessionNotifyEventHandler?.Invoke(proxyContext, TcpSessionNotify.OnClosed); + proxyContext.DataReceivedEventHandler -= DataReceivedEventHandler; + proxyContext.DataSendEventHandler -= DataSendEventHandler; + proxyContext.Dispose(); + } + _currentSession.Close(true); + } + } +} diff --git a/SiMay.Net.SessionProvider/TcpSessionConnection/TcpSocketSessionContext.cs b/SiMay.Net.SessionProvider/TcpSessionConnection/TcpSocketSessionContext.cs new file mode 100644 index 0000000..3de8bdc --- /dev/null +++ b/SiMay.Net.SessionProvider/TcpSessionConnection/TcpSocketSessionContext.cs @@ -0,0 +1,64 @@ +using SiMay.Net.SessionProvider.Core; +using SiMay.Sockets.Tcp; +using SiMay.Sockets.Tcp.Session; +using System; +using System.Collections.Generic; +using System.Linq; +using System.Net.Sockets; +using System.Text; + +namespace SiMay.Net.SessionProvider +{ + public class TcpSocketSessionContext : SessionProviderContext + { + public TcpSocketSessionContext(TcpSocketSaeaSession session) + { + CurrentSession = session; + } + /// + /// 发送长度 + /// + public override int SendTransferredBytes => CurrentSession.SendTransferredBytes; + + /// + /// 接受长度 + /// + public override int ReceiveTransferredBytes => CurrentSession.ReceiveBytesTransferred; + + /// + /// 完成缓冲区 + /// + public override byte[] CompletedBuffer => CurrentSession.CompletedBuffer; + + /// + /// 发送数据 + /// + /// + /// + /// + public override void SendAsync(byte[] data, int offset, int length) => CurrentSession.SendAsync(data, offset, length); + + /// + /// 关闭会话 + /// + public override void SessionClose() => CurrentSession.Close(true); + + /// + /// Socket设置 + /// + /// + /// + /// + public override void SetSocketOptions(SocketOptionLevel optionLevel, SocketOptionName optionName, object optionValue) + { + if (optionValue is byte[] bytes) + CurrentSession.Socket.SetSocketOption(optionLevel, optionName, bytes); + else if (optionValue is int num) + CurrentSession.Socket.SetSocketOption(optionLevel, optionName, num); + else if (optionValue is bool b) + CurrentSession.Socket.SetSocketOption(optionLevel, optionName, b); + else + CurrentSession.Socket.SetSocketOption(optionLevel, optionName, optionValue); + } + } +} diff --git a/SiMay.Net.SessionProviderService/AccessKeyExamine.cs b/SiMay.Net.SessionProviderService/AccessKeyExamine.cs deleted file mode 100644 index d557ce1..0000000 --- a/SiMay.Net.SessionProviderService/AccessKeyExamine.cs +++ /dev/null @@ -1,26 +0,0 @@ -using System; -using System.Collections.Generic; -using System.Linq; -using System.Text; -using System.Threading.Tasks; - -namespace SiMay.Net.SessionProviderService -{ - public class AccessKeyExamine - { - public static long ServiceAccessKey = 0; - - static AccessKeyExamine() - { - ServiceAccessKey = long.Parse(ApplicationConfiguration.ServiceAccessKey); - } - - public static bool CheckOut(long key) - { - if (key == ServiceAccessKey) - return true; - else - return false; - } - } -} diff --git a/SiMay.Net.SessionProviderService/App.config b/SiMay.Net.SessionProviderService/App.config index ecdcf8a..bae5d6d 100644 --- a/SiMay.Net.SessionProviderService/App.config +++ b/SiMay.Net.SessionProviderService/App.config @@ -1,6 +1,6 @@ - + diff --git a/SiMay.Net.SessionProviderService/ApplicationConfiguration.cs b/SiMay.Net.SessionProviderService/ApplicationConfiguration.cs index 508b14c..ecdbf0f 100644 --- a/SiMay.Net.SessionProviderService/ApplicationConfiguration.cs +++ b/SiMay.Net.SessionProviderService/ApplicationConfiguration.cs @@ -2,6 +2,7 @@ using SiMay.Net.SessionProvider.Core; using System; using System.Collections.Generic; +using System.IO; using System.Linq; using System.Text; using System.Threading.Tasks; @@ -10,29 +11,70 @@ namespace SiMay.Net.SessionProviderService { public class ApplicationConfiguration { - private static string IniFilePath = Environment.CurrentDirectory + @"\SiMayConfig.ini"; - public static string IPAddress + private static string FileName = Environment.CurrentDirectory + @"\SiMayConfig.ini"; + + public static string LogFileName { get; set; } = Path.Combine(Environment.CurrentDirectory, "SiMay.log"); + /// + /// 本机地址 + /// + public static string LoalAddress + { + get { return IniConfigHelper.GetValue("ServiceConfig", "IPAddress", "0.0.0.0", FileName); } + set { IniConfigHelper.SetValue("ServiceConfig", "IPAddress", value, FileName); } + } + + /// + /// 端口 + /// + public static int Port + { + get { return int.Parse(IniConfigHelper.GetValue("ServiceConfig", "Port", "522", FileName)); } + set { IniConfigHelper.SetValue("ServiceConfig", "Port", value.ToString(), FileName); } + } + + /// + /// 连接挂起队列 + /// + public static int Backlog + { + get { return int.Parse(IniConfigHelper.GetValue("ServiceConfig", "Backlog", "0", FileName)); } + set { IniConfigHelper.SetValue("ServiceConfig", "Backlog", value.ToString(), FileName); } + } + + /// + /// 是否允许匿名登陆 + /// + public static bool AnonyMous { - get { return IniConfigHelper.GetValue("ServiceConfig", "IPAddress", "0.0.0.0", IniFilePath); } - set { IniConfigHelper.SetValue("ServiceConfig", "IPAddress", value, IniFilePath); } + get { return bool.Parse(IniConfigHelper.GetValue("ServiceConfig", "AnonyMous", "true", FileName)); } + set { IniConfigHelper.SetValue("ServiceConfig", "AnonyMous", value.ToString(), FileName); } } - public static string Port + /// + /// 允许登陆的AccessId + /// + public static string AccessIds { - get { return IniConfigHelper.GetValue("ServiceConfig", "Port", "522", IniFilePath); } - set { IniConfigHelper.SetValue("ServiceConfig", "Port", value, IniFilePath); } + get { return IniConfigHelper.GetValue("ServiceConfig", "AccessIds", "123456789", FileName); } + set { IniConfigHelper.SetValue("ServiceConfig", "AccessIds", value.ToString(), FileName); } } - public static string Backlog + /// + /// 主控端登陆密码 + /// + public static long MainAppAccessKey { - get { return IniConfigHelper.GetValue("ServiceConfig", "Backlog", "0", IniFilePath); } - set { IniConfigHelper.SetValue("ServiceConfig", "Backlog", value, IniFilePath); } + get { return long.Parse(IniConfigHelper.GetValue("ServiceConfig", "MainAppAccessKey", "5200", FileName)); } + set { IniConfigHelper.SetValue("ServiceConfig", "MainAppAccessKey", value.ToString(), FileName); } } - public static string ServiceAccessKey + /// + /// 连接密码 + /// + public static long AccessKey { - get { return IniConfigHelper.GetValue("ServiceConfig", "ServiceAccessKey", "522222", IniFilePath); } - set { IniConfigHelper.SetValue("ServiceConfig", "ServiceAccessKey", value, IniFilePath); } + get { return long.Parse(IniConfigHelper.GetValue("ServiceConfig", "AccessKey", "5200", FileName)); } + set { IniConfigHelper.SetValue("ServiceConfig", "AccessKey", value.ToString(), FileName); } } } } diff --git a/SiMay.Net.SessionProviderService/ChannelViewItem/ChannelViewItem.cs b/SiMay.Net.SessionProviderService/ChannelViewItem/ChannelViewItem.cs new file mode 100644 index 0000000..07130b9 --- /dev/null +++ b/SiMay.Net.SessionProviderService/ChannelViewItem/ChannelViewItem.cs @@ -0,0 +1,48 @@ +using SiMay.Net.SessionProviderServiceCore; +using SiMay.Basic; +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; +using System.Windows.Forms; + +namespace SiMay.Net.SessionProviderService +{ + public class ChannelViewItem : ListViewItem + { + private ListViewSubItem _viewSubItem; + public ChannelViewItem(TcpSessionChannelDispatcher channelDispatcher) + { + _viewSubItem = new ListViewSubItem(this, "0.00/0.00"); + this.Text = channelDispatcher.DispatcherId.ToString(); + this.SubItems.Add(DateTime.Now.ToString()); + this.SubItems.Add(channelDispatcher.ConnectionWorkType.GetDescription()); + this.SubItems.Add(_viewSubItem); + ChannelDispatcher = channelDispatcher; + channelDispatcher.SendStreamLengthEventHandler += SendStreamLengthEventHandler; + channelDispatcher.ReceiveStreamLengthEventHandler += ReceiveStreamLengthEventHandler; + } + + private void ReceiveStreamLengthEventHandler(TcpSessionChannelDispatcher channelDispatcher, long length) => ReceiveStreamLength += length; + + private void SendStreamLengthEventHandler(TcpSessionChannelDispatcher channelDispatcher, long length) => SendStreamLength += length; + + /// + /// 发送长度 + /// + public long SendStreamLength { get; set; } + + /// + /// 接受长度 + /// + public long ReceiveStreamLength { get; set; } + + public void SetVelocityText(long s, long r) + { + _viewSubItem.Text = $"{((float)s / 1024).ToString("0.00")} KB/{((float)r / 1024).ToString("0.00")} KB"; + } + + public TcpSessionChannelDispatcher ChannelDispatcher { get; private set; } + } +} diff --git a/SiMay.Net.SessionProviderService/Delagate/TcpChannelContextNotifyHandler.cs b/SiMay.Net.SessionProviderService/Delagate/TcpChannelContextNotifyHandler.cs deleted file mode 100644 index 11ef91d..0000000 --- a/SiMay.Net.SessionProviderService/Delagate/TcpChannelContextNotifyHandler.cs +++ /dev/null @@ -1,11 +0,0 @@ -using System; -using System.Collections.Generic; -using System.Linq; -using System.Text; -using System.Threading.Tasks; - -namespace SiMay.Net.SessionProviderService.Delagate -{ - public delegate void TcpChannelContextNotifyHandler(T1 arg1, T2 arg2); - public delegate void TcpChannelContextNotifyHandler(T1 arg1, T2 arg2, T3 arg3); -} diff --git a/SiMay.Net.SessionProviderService/LogShowQueueHelper.cs b/SiMay.Net.SessionProviderService/LogShowQueueHelper.cs deleted file mode 100644 index 3fe7502..0000000 --- a/SiMay.Net.SessionProviderService/LogShowQueueHelper.cs +++ /dev/null @@ -1,28 +0,0 @@ -using System; -using System.Collections.Generic; -using System.Linq; -using System.Text; -using System.Threading.Tasks; - -namespace SiMay.Net.SessionProviderService -{ - public class Log - { - public int Success { get; set; } - - public string log { get; set; } - } - public class LogShowQueueHelper - { - public static Queue LogQueue = new Queue(); - - public static void WriteLog(string log, string status = "ok") - { - LogQueue.Enqueue(new Log() - { - Success = status == "ok" ? 0 : 1, - log = log - }); - } - } -} diff --git a/SiMay.Net.SessionProviderService/MessageHelper.cs b/SiMay.Net.SessionProviderService/MessageHelper.cs deleted file mode 100644 index 2a49d86..0000000 --- a/SiMay.Net.SessionProviderService/MessageHelper.cs +++ /dev/null @@ -1,26 +0,0 @@ -using SiMay.Net.SessionProvider.Core; -using System; -using System.Collections.Generic; -using System.Linq; -using System.Text; -using System.Threading.Tasks; - -namespace SiMay.Net.SessionProviderService -{ - public class MessageHelper - { - public static byte[] CommandCopyTo(MsgCommand cmd, byte[] data) - { - byte[] bytes = new byte[data.Length + 1]; - bytes[0] = (byte)cmd; - data.CopyTo(bytes, 1); - - return bytes; - } - - public static byte[] CommandCopyTo(MsgCommand cmd) - { - return new byte[] { (byte)cmd }; - } - } -} diff --git a/SiMay.Net.SessionProviderService/Notify/ManagerChannelNotify.cs b/SiMay.Net.SessionProviderService/Notify/ManagerChannelNotify.cs deleted file mode 100644 index bd7e87d..0000000 --- a/SiMay.Net.SessionProviderService/Notify/ManagerChannelNotify.cs +++ /dev/null @@ -1,13 +0,0 @@ -using System; -using System.Collections.Generic; -using System.Linq; -using System.Text; -using System.Threading.Tasks; - -namespace SiMay.Net.SessionProviderService.Notify -{ - public enum ManagerChannelNotify - { - - } -} diff --git a/SiMay.Net.SessionProviderService/OnChannelListViewItem/ChannelListViewItem.cs b/SiMay.Net.SessionProviderService/OnChannelListViewItem/ChannelListViewItem.cs deleted file mode 100644 index 87abc1c..0000000 --- a/SiMay.Net.SessionProviderService/OnChannelListViewItem/ChannelListViewItem.cs +++ /dev/null @@ -1,18 +0,0 @@ -using System; -using System.Collections.Generic; -using System.Linq; -using System.Text; -using System.Threading.Tasks; -using System.Windows.Forms; - -namespace SiMay.Net.SessionProviderService.OnChannelListViewItem -{ - public class ChannelListViewItem : ListViewItem - { - public ChannelListViewItem(TcpSessionChannelContext context) - { - TcpChannelContext = context; - } - public TcpSessionChannelContext TcpChannelContext { get; set; } - } -} diff --git a/SiMay.Net.SessionProviderService/Program.cs b/SiMay.Net.SessionProviderService/Program.cs index c772513..4fddf00 100644 --- a/SiMay.Net.SessionProviderService/Program.cs +++ b/SiMay.Net.SessionProviderService/Program.cs @@ -30,7 +30,7 @@ namespace SiMay.Net.SessionProviderService Exception e = (Exception)ex.ExceptionObject; LogHelper.WriteLog("子线程异常:" + Environment.NewLine + "异常信息:" + e.Message + Environment.NewLine + - "异常堆栈:" + e.StackTrace + Environment.NewLine); + "异常堆栈:" + e.StackTrace + Environment.NewLine, ApplicationConfiguration.LogFileName); } private static void Application_ThreadException(object sender, ThreadExceptionEventArgs ex) @@ -39,7 +39,7 @@ namespace SiMay.Net.SessionProviderService LogHelper.WriteLog("UI异常:" + Environment.NewLine + "异常信息:" + e.Message + Environment.NewLine + - "异常堆栈:" + e.StackTrace + Environment.NewLine); + "异常堆栈:" + e.StackTrace + Environment.NewLine, ApplicationConfiguration.LogFileName); } } } diff --git a/SiMay.Net.SessionProviderService/SessionProviderService.Designer.cs b/SiMay.Net.SessionProviderService/SessionProviderService.Designer.cs index c08a3f2..9b8198b 100644 --- a/SiMay.Net.SessionProviderService/SessionProviderService.Designer.cs +++ b/SiMay.Net.SessionProviderService/SessionProviderService.Designer.cs @@ -30,6 +30,7 @@ { this.components = new System.ComponentModel.Container(); this.channelListView = new System.Windows.Forms.ListView(); + this.channel_id = ((System.Windows.Forms.ColumnHeader)(new System.Windows.Forms.ColumnHeader())); this.create_time = ((System.Windows.Forms.ColumnHeader)(new System.Windows.Forms.ColumnHeader())); this.channel_type = ((System.Windows.Forms.ColumnHeader)(new System.Windows.Forms.ColumnHeader())); this.channel_rate = ((System.Windows.Forms.ColumnHeader)(new System.Windows.Forms.ColumnHeader())); @@ -40,10 +41,10 @@ this.lableStatrTime = new System.Windows.Forms.ToolStripStatusLabel(); this.toolStripStatusLabel3 = new System.Windows.Forms.ToolStripStatusLabel(); this.toolStripStatusLabel2 = new System.Windows.Forms.ToolStripStatusLabel(); - this.labelUpload = new System.Windows.Forms.ToolStripStatusLabel(); + this.lbUpload = new System.Windows.Forms.ToolStripStatusLabel(); this.toolStripStatusLabel4 = new System.Windows.Forms.ToolStripStatusLabel(); this.toolStripStatusLabel6 = new System.Windows.Forms.ToolStripStatusLabel(); - this.labelReceive = new System.Windows.Forms.ToolStripStatusLabel(); + this.lbReceive = new System.Windows.Forms.ToolStripStatusLabel(); this.toolStripStatusLabel8 = new System.Windows.Forms.ToolStripStatusLabel(); this.label1 = new System.Windows.Forms.Label(); this.lableIPAddress = new System.Windows.Forms.Label(); @@ -59,6 +60,7 @@ this.toolStripMenuItem1 = new System.Windows.Forms.ToolStripMenuItem(); this.toolStripMenuItem2 = new System.Windows.Forms.ToolStripMenuItem(); this.清空日志ToolStripMenuItem1 = new System.Windows.Forms.ToolStripMenuItem(); + this.timerFlowCalac = new System.Windows.Forms.Timer(this.components); this.channelListContext.SuspendLayout(); this.statusStrip1.SuspendLayout(); ((System.ComponentModel.ISupportInitialize)(this.splitContainer1)).BeginInit(); @@ -72,19 +74,27 @@ // this.channelListView.CheckBoxes = true; this.channelListView.Columns.AddRange(new System.Windows.Forms.ColumnHeader[] { + this.channel_id, this.create_time, this.channel_type, this.channel_rate}); this.channelListView.ContextMenuStrip = this.channelListContext; this.channelListView.Dock = System.Windows.Forms.DockStyle.Fill; this.channelListView.FullRowSelect = true; + this.channelListView.HideSelection = false; this.channelListView.Location = new System.Drawing.Point(0, 0); + this.channelListView.Margin = new System.Windows.Forms.Padding(4); this.channelListView.Name = "channelListView"; - this.channelListView.Size = new System.Drawing.Size(722, 189); + this.channelListView.Size = new System.Drawing.Size(963, 236); this.channelListView.TabIndex = 0; this.channelListView.UseCompatibleStateImageBehavior = false; this.channelListView.View = System.Windows.Forms.View.Details; // + // channel_id + // + this.channel_id.Text = "Id"; + this.channel_id.Width = 150; + // // create_time // this.create_time.Text = "连接时间"; @@ -93,12 +103,12 @@ // channel_type // this.channel_type.Text = "连接类型"; - this.channel_type.Width = 100; + this.channel_type.Width = 150; // // channel_rate // - this.channel_rate.Text = "实时速率(s/kb)"; - this.channel_rate.Width = 100; + this.channel_rate.Text = "实时速率(上行/下行)"; + this.channel_rate.Width = 175; // // channelListContext // @@ -107,139 +117,147 @@ this.toolStripMenuItem3}); this.channelListContext.Name = "logsContext"; this.channelListContext.RenderMode = System.Windows.Forms.ToolStripRenderMode.Professional; - this.channelListContext.Size = new System.Drawing.Size(125, 26); + this.channelListContext.Size = new System.Drawing.Size(139, 28); this.channelListContext.Opening += new System.ComponentModel.CancelEventHandler(this.channelListContext_Opening); // // toolStripMenuItem3 // this.toolStripMenuItem3.Name = "toolStripMenuItem3"; - this.toolStripMenuItem3.Size = new System.Drawing.Size(124, 22); + this.toolStripMenuItem3.Size = new System.Drawing.Size(138, 24); this.toolStripMenuItem3.Text = "关闭连接"; this.toolStripMenuItem3.Click += new System.EventHandler(this.toolStripMenuItem3_Click); // // statusStrip1 // + this.statusStrip1.ImageScalingSize = new System.Drawing.Size(20, 20); this.statusStrip1.Items.AddRange(new System.Windows.Forms.ToolStripItem[] { this.toolStripStatusLabel1, this.lableStatrTime, this.toolStripStatusLabel3, this.toolStripStatusLabel2, - this.labelUpload, + this.lbUpload, this.toolStripStatusLabel4, this.toolStripStatusLabel6, - this.labelReceive, + this.lbReceive, this.toolStripStatusLabel8}); - this.statusStrip1.Location = new System.Drawing.Point(0, 470); + this.statusStrip1.Location = new System.Drawing.Point(0, 589); this.statusStrip1.Name = "statusStrip1"; - this.statusStrip1.Size = new System.Drawing.Size(722, 22); + this.statusStrip1.Padding = new System.Windows.Forms.Padding(1, 0, 19, 0); + this.statusStrip1.Size = new System.Drawing.Size(963, 26); this.statusStrip1.TabIndex = 1; this.statusStrip1.Text = "statusStrip1"; // // toolStripStatusLabel1 // this.toolStripStatusLabel1.Name = "toolStripStatusLabel1"; - this.toolStripStatusLabel1.Size = new System.Drawing.Size(59, 17); + this.toolStripStatusLabel1.Size = new System.Drawing.Size(73, 20); this.toolStripStatusLabel1.Text = "启动时间:"; // // lableStatrTime // this.lableStatrTime.Name = "lableStatrTime"; - this.lableStatrTime.Size = new System.Drawing.Size(131, 17); + this.lableStatrTime.Size = new System.Drawing.Size(167, 20); this.lableStatrTime.Text = "toolStripStatusLabel1"; // // toolStripStatusLabel3 // this.toolStripStatusLabel3.Name = "toolStripStatusLabel3"; - this.toolStripStatusLabel3.Size = new System.Drawing.Size(311, 17); + this.toolStripStatusLabel3.Size = new System.Drawing.Size(451, 20); this.toolStripStatusLabel3.Spring = true; // // toolStripStatusLabel2 // this.toolStripStatusLabel2.Name = "toolStripStatusLabel2"; - this.toolStripStatusLabel2.Size = new System.Drawing.Size(35, 17); - this.toolStripStatusLabel2.Text = "上传:"; + this.toolStripStatusLabel2.Size = new System.Drawing.Size(43, 20); + this.toolStripStatusLabel2.Text = "上行:"; // - // labelUpload + // lbUpload // - this.labelUpload.Name = "labelUpload"; - this.labelUpload.Size = new System.Drawing.Size(32, 17); - this.labelUpload.Text = "0.00"; + this.lbUpload.Name = "lbUpload"; + this.lbUpload.Size = new System.Drawing.Size(40, 20); + this.lbUpload.Text = "0.00"; // // toolStripStatusLabel4 // this.toolStripStatusLabel4.Name = "toolStripStatusLabel4"; - this.toolStripStatusLabel4.Size = new System.Drawing.Size(36, 17); + this.toolStripStatusLabel4.Size = new System.Drawing.Size(43, 20); this.toolStripStatusLabel4.Text = "KB/S"; // // toolStripStatusLabel6 // this.toolStripStatusLabel6.Name = "toolStripStatusLabel6"; - this.toolStripStatusLabel6.Size = new System.Drawing.Size(35, 17); - this.toolStripStatusLabel6.Text = "下传:"; + this.toolStripStatusLabel6.Size = new System.Drawing.Size(43, 20); + this.toolStripStatusLabel6.Text = "下行:"; // - // labelReceive + // lbReceive // - this.labelReceive.Name = "labelReceive"; - this.labelReceive.Size = new System.Drawing.Size(32, 17); - this.labelReceive.Text = "0.00"; + this.lbReceive.Name = "lbReceive"; + this.lbReceive.Size = new System.Drawing.Size(40, 20); + this.lbReceive.Text = "0.00"; // // toolStripStatusLabel8 // this.toolStripStatusLabel8.Name = "toolStripStatusLabel8"; - this.toolStripStatusLabel8.Size = new System.Drawing.Size(36, 17); + this.toolStripStatusLabel8.Size = new System.Drawing.Size(43, 20); this.toolStripStatusLabel8.Text = "KB/S"; // // label1 // this.label1.AutoSize = true; - this.label1.Location = new System.Drawing.Point(12, 7); + this.label1.Location = new System.Drawing.Point(16, 9); + this.label1.Margin = new System.Windows.Forms.Padding(4, 0, 4, 0); this.label1.Name = "label1"; - this.label1.Size = new System.Drawing.Size(23, 12); + this.label1.Size = new System.Drawing.Size(31, 15); this.label1.TabIndex = 2; this.label1.Text = "IP:"; // // lableIPAddress // this.lableIPAddress.AutoSize = true; - this.lableIPAddress.Location = new System.Drawing.Point(41, 7); + this.lableIPAddress.Location = new System.Drawing.Point(55, 9); + this.lableIPAddress.Margin = new System.Windows.Forms.Padding(4, 0, 4, 0); this.lableIPAddress.Name = "lableIPAddress"; - this.lableIPAddress.Size = new System.Drawing.Size(47, 12); + this.lableIPAddress.Size = new System.Drawing.Size(63, 15); this.lableIPAddress.TabIndex = 3; this.lableIPAddress.Text = "0.0.0.0"; // // label3 // this.label3.AutoSize = true; - this.label3.Location = new System.Drawing.Point(148, 7); + this.label3.Location = new System.Drawing.Point(197, 9); + this.label3.Margin = new System.Windows.Forms.Padding(4, 0, 4, 0); this.label3.Name = "label3"; - this.label3.Size = new System.Drawing.Size(35, 12); + this.label3.Size = new System.Drawing.Size(47, 15); this.label3.TabIndex = 4; this.label3.Text = "Port:"; // // labelPort // this.labelPort.AutoSize = true; - this.labelPort.Location = new System.Drawing.Point(189, 7); + this.labelPort.Location = new System.Drawing.Point(252, 9); + this.labelPort.Margin = new System.Windows.Forms.Padding(4, 0, 4, 0); this.labelPort.Name = "labelPort"; - this.labelPort.Size = new System.Drawing.Size(29, 12); + this.labelPort.Size = new System.Drawing.Size(39, 15); this.labelPort.TabIndex = 5; this.labelPort.Text = "5200"; // // label5 // this.label5.AutoSize = true; - this.label5.Location = new System.Drawing.Point(553, 7); + this.label5.Location = new System.Drawing.Point(737, 9); + this.label5.Margin = new System.Windows.Forms.Padding(4, 0, 4, 0); this.label5.Name = "label5"; - this.label5.Size = new System.Drawing.Size(83, 12); + this.label5.Size = new System.Drawing.Size(105, 15); this.label5.TabIndex = 6; this.label5.Text = "会话连接数量:"; // // lableConnectionCount // this.lableConnectionCount.AutoSize = true; - this.lableConnectionCount.Location = new System.Drawing.Point(642, 7); + this.lableConnectionCount.Location = new System.Drawing.Point(856, 9); + this.lableConnectionCount.Margin = new System.Windows.Forms.Padding(4, 0, 4, 0); this.lableConnectionCount.Name = "lableConnectionCount"; - this.lableConnectionCount.Size = new System.Drawing.Size(11, 12); + this.lableConnectionCount.Size = new System.Drawing.Size(15, 15); this.lableConnectionCount.TabIndex = 7; this.lableConnectionCount.Text = "0"; // @@ -248,7 +266,8 @@ this.splitContainer1.Anchor = ((System.Windows.Forms.AnchorStyles)((((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Bottom) | System.Windows.Forms.AnchorStyles.Left) | System.Windows.Forms.AnchorStyles.Right))); - this.splitContainer1.Location = new System.Drawing.Point(0, 24); + this.splitContainer1.Location = new System.Drawing.Point(0, 30); + this.splitContainer1.Margin = new System.Windows.Forms.Padding(4); this.splitContainer1.Name = "splitContainer1"; this.splitContainer1.Orientation = System.Windows.Forms.Orientation.Horizontal; // @@ -259,8 +278,8 @@ // splitContainer1.Panel2 // this.splitContainer1.Panel2.Controls.Add(this.logList); - this.splitContainer1.Size = new System.Drawing.Size(722, 443); - this.splitContainer1.SplitterDistance = 189; + this.splitContainer1.Size = new System.Drawing.Size(963, 554); + this.splitContainer1.SplitterDistance = 236; this.splitContainer1.SplitterWidth = 1; this.splitContainer1.TabIndex = 8; // @@ -272,9 +291,11 @@ this.logList.ContextMenuStrip = this.logContext; this.logList.Dock = System.Windows.Forms.DockStyle.Fill; this.logList.FullRowSelect = true; + this.logList.HideSelection = false; this.logList.Location = new System.Drawing.Point(0, 0); + this.logList.Margin = new System.Windows.Forms.Padding(4); this.logList.Name = "logList"; - this.logList.Size = new System.Drawing.Size(722, 253); + this.logList.Size = new System.Drawing.Size(963, 317); this.logList.TabIndex = 1; this.logList.UseCompatibleStateImageBehavior = false; this.logList.View = System.Windows.Forms.View.Details; @@ -282,12 +303,12 @@ // log_create_time // this.log_create_time.Text = "发生时间"; - this.log_create_time.Width = 150; + this.log_create_time.Width = 114; // // log // this.log.Text = "事件信息"; - this.log.Width = 500; + this.log.Width = 400; // // logContext // @@ -298,34 +319,40 @@ this.清空日志ToolStripMenuItem1}); this.logContext.Name = "logsContext"; this.logContext.RenderMode = System.Windows.Forms.ToolStripRenderMode.Professional; - this.logContext.Size = new System.Drawing.Size(125, 70); + this.logContext.Size = new System.Drawing.Size(139, 76); // // toolStripMenuItem1 // this.toolStripMenuItem1.Name = "toolStripMenuItem1"; - this.toolStripMenuItem1.Size = new System.Drawing.Size(124, 22); + this.toolStripMenuItem1.Size = new System.Drawing.Size(138, 24); this.toolStripMenuItem1.Text = "复制日志"; this.toolStripMenuItem1.Click += new System.EventHandler(this.toolStripMenuItem1_Click); // // toolStripMenuItem2 // this.toolStripMenuItem2.Name = "toolStripMenuItem2"; - this.toolStripMenuItem2.Size = new System.Drawing.Size(124, 22); + this.toolStripMenuItem2.Size = new System.Drawing.Size(138, 24); this.toolStripMenuItem2.Text = "删除日志"; this.toolStripMenuItem2.Click += new System.EventHandler(this.toolStripMenuItem2_Click); // // 清空日志ToolStripMenuItem1 // this.清空日志ToolStripMenuItem1.Name = "清空日志ToolStripMenuItem1"; - this.清空日志ToolStripMenuItem1.Size = new System.Drawing.Size(124, 22); + this.清空日志ToolStripMenuItem1.Size = new System.Drawing.Size(138, 24); this.清空日志ToolStripMenuItem1.Text = "清空日志"; this.清空日志ToolStripMenuItem1.Click += new System.EventHandler(this.清空日志ToolStripMenuItem1_Click); // + // timerFlowCalac + // + this.timerFlowCalac.Enabled = true; + this.timerFlowCalac.Interval = 1000; + this.timerFlowCalac.Tick += new System.EventHandler(this.timerFlowCalac_Tick); + // // SessionProviderService // - this.AutoScaleDimensions = new System.Drawing.SizeF(6F, 12F); + this.AutoScaleDimensions = new System.Drawing.SizeF(8F, 15F); this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font; - this.ClientSize = new System.Drawing.Size(722, 492); + this.ClientSize = new System.Drawing.Size(963, 615); this.Controls.Add(this.splitContainer1); this.Controls.Add(this.lableConnectionCount); this.Controls.Add(this.label5); @@ -334,6 +361,7 @@ this.Controls.Add(this.lableIPAddress); this.Controls.Add(this.label1); this.Controls.Add(this.statusStrip1); + this.Margin = new System.Windows.Forms.Padding(4); this.Name = "SessionProviderService"; this.StartPosition = System.Windows.Forms.FormStartPosition.CenterScreen; this.Text = "SiMay中间会话服务"; @@ -377,13 +405,15 @@ private System.Windows.Forms.ToolStripMenuItem 清空日志ToolStripMenuItem1; private System.Windows.Forms.ToolStripStatusLabel toolStripStatusLabel3; private System.Windows.Forms.ToolStripStatusLabel toolStripStatusLabel2; - private System.Windows.Forms.ToolStripStatusLabel labelUpload; + private System.Windows.Forms.ToolStripStatusLabel lbUpload; private System.Windows.Forms.ToolStripStatusLabel toolStripStatusLabel4; private System.Windows.Forms.ToolStripStatusLabel toolStripStatusLabel6; - private System.Windows.Forms.ToolStripStatusLabel labelReceive; + private System.Windows.Forms.ToolStripStatusLabel lbReceive; private System.Windows.Forms.ToolStripStatusLabel toolStripStatusLabel8; private System.Windows.Forms.ContextMenuStrip channelListContext; private System.Windows.Forms.ToolStripMenuItem toolStripMenuItem3; + private System.Windows.Forms.ColumnHeader channel_id; + private System.Windows.Forms.Timer timerFlowCalac; } } diff --git a/SiMay.Net.SessionProviderService/SessionProviderService.cs b/SiMay.Net.SessionProviderService/SessionProviderService.cs index 7b70f85..9ca6e9b 100644 --- a/SiMay.Net.SessionProviderService/SessionProviderService.cs +++ b/SiMay.Net.SessionProviderService/SessionProviderService.cs @@ -1,25 +1,17 @@ -using SiMay.Net.SessionProvider.Core; -using SiMay.Net.SessionProviderService.OnChannelListViewItem; -using SiMay.Net.SessionProviderService.Properties; -using SiMay.Sockets.Tcp; -using SiMay.Sockets.Tcp.Server; -using SiMay.Sockets.Tcp.Session; -using SiMay.Sockets.Tcp.TcpConfiguration; -using System; -using System.Collections.Generic; +using System; using System.ComponentModel; -using System.Data; using System.Diagnostics; -using System.Drawing; using System.IO; using System.Linq; using System.Net; -using System.Runtime.InteropServices; -using System.Text; using System.Threading; -using System.Threading.Tasks; using System.Windows.Forms; -using static SiMay.Net.SessionProvider.Core.Win32Api; +using SiMay.Basic; +using SiMay.Net.SessionProvider.Core; +using SiMay.Net.SessionProviderService.Properties; +using SiMay.Net.SessionProviderServiceCore; +using static System.Windows.Forms.ListViewItem; +using static SiMay.Net.SessionProviderService.Win32; namespace SiMay.Net.SessionProviderService { @@ -27,179 +19,12 @@ namespace SiMay.Net.SessionProviderService { private const Int32 IDM_OPTIONS = 1000; private const Int32 IDM_RUNLOG = 1001; + public SessionProviderService() { InitializeComponent(); } - float _uploadTransferBytes; - float _receiveTransferBytes; - - ImageList _log_imgList; - - List _channelContexts = new List(); - TcpSocketSaeaServer _server; - - TcpSessionChannelContext _manager_channel; - int _managerChannelLoginSign = 0; - - int _connectionCount = 0; - private void SessionProviderService_Load(object sender, EventArgs e) - { - - this.Text = "SiMay中间会话服务-IOASJHD BEAT " + System.Reflection.Assembly.GetExecutingAssembly().GetName().Version.ToString(); - - IntPtr sysMenuHandle = GetSystemMenu(this.Handle, false); - - InsertMenu(sysMenuHandle, 7, MF_SEPARATOR, 0, null); - InsertMenu(sysMenuHandle, 8, MF_BYPOSITION, IDM_OPTIONS, "系统设置"); - InsertMenu(sysMenuHandle, 9, MF_BYPOSITION, IDM_RUNLOG, "运行日志"); - - _log_imgList = new ImageList(); - _log_imgList.Images.Add("ok", Resources.ok); - _log_imgList.Images.Add("err", Resources.erro); - - logList.SmallImageList = _log_imgList; - - string address = ApplicationConfiguration.IPAddress; - string port = ApplicationConfiguration.Port; - - this.lableIPAddress.Text = address; - this.labelPort.Text = port; - this.lableStatrTime.Text = DateTime.Now.ToString(); - var ipe = new IPEndPoint(IPAddress.Parse(address), int.Parse(port)); - - - var serverConfig = new TcpSocketSaeaServerConfiguration(); - serverConfig.ReuseAddress = false; - serverConfig.KeepAlive = true; - serverConfig.KeepAliveInterval = 5000; - serverConfig.KeepAliveSpanTime = 1000; - serverConfig.PendingConnectionBacklog = int.Parse(ApplicationConfiguration.Backlog); - - _server = TcpSocketsFactory.CreateServerAgent(TcpSocketSaeaSessionType.Full, serverConfig, (notify, session) => - { - switch (notify) - { - case TcpSocketCompletionNotify.OnConnected: - _connectionCount++; - - this.Invoke(new Action(() => - { - this.lableConnectionCount.Text = _connectionCount.ToString(); - })); - - //创建通道上下文,等待确认通道类型 - TcpSessionChannelContext context = new TcpSessionChannelContext(session); - context.OnChannelTypeCheckEventHandler += Context_TcpAwaitnotifyProc; - - _channelContexts.Add(context); - break; - case TcpSocketCompletionNotify.OnSend: - this._uploadTransferBytes += session.SendTransferredBytes; - break; - case TcpSocketCompletionNotify.OnDataReceiveing: - this._receiveTransferBytes += session.ReceiveBytesTransferred; - - ((TcpSessionChannelContext)session.AppTokens[0]).OnMessage(session); - break; - case TcpSocketCompletionNotify.OnClosed: - _connectionCount--; - - this.Invoke(new Action(() => - { - this.lableConnectionCount.Text = _connectionCount.ToString(); - })); - - this.SessionClosed(session); - break; - default: - break; - } - - }); - try - { - _server.Listen(ipe); - LogShowQueueHelper.WriteLog("SiMay中间会话服务端口" + port + "启动成功!"); - } - catch - { - LogShowQueueHelper.WriteLog("SiMay中间会话服务端口" + port + "启动失败!", "err"); - } - - System.Timers.Timer timer = new System.Timers.Timer(); - timer.Interval = 100; - timer.Elapsed += Timer_Elapsed; - timer.Start(); - - System.Timers.Timer flow_timer = new System.Timers.Timer(); - flow_timer.Interval = 1000; - flow_timer.Elapsed += Flow_timer_Elapsed; - flow_timer.Start(); - } - - private void Flow_timer_Elapsed(object sender, System.Timers.ElapsedEventArgs e) - { - this.Invoke(new Action(() => - { - this.labelUpload.Text = (this._uploadTransferBytes / 1024).ToString("0.00"); - this.labelReceive.Text = (this._receiveTransferBytes / 1024).ToString("0.00"); - - this._receiveTransferBytes = 0; - this._uploadTransferBytes = 0; - })); - } - - private void Timer_Elapsed(object sender, System.Timers.ElapsedEventArgs e) - { - while (LogShowQueueHelper.LogQueue.Count != 0) - { - if (LogShowQueueHelper.LogQueue.Count > 0) - { - Log log = LogShowQueueHelper.LogQueue.Dequeue(); - - - - this.Invoke(new Action(() => - { - WriteRuninglog(log.log, log.Success == 0 ? "ok" : "err"); - })); - } - } - } - /// - /// 输出日志 - /// - /// - /// - private void WriteRuninglog(string log, string key = "ok") - { - ListViewItem lv = new ListViewItem(); - lv.ImageKey = key; - lv.Text = DateTime.Now.ToString(); - lv.SubItems.Add(log); - - LogHelper.WriteLog(log, "OnRun.log"); - - if (logList.Items.Count >= 1) - logList.Items.Insert(1, lv); - else - logList.Items.Insert(0, lv); - } - /// - /// 清除日志 - /// - private void Clearlogs() - { - int i = 0; - foreach (ListViewItem item in logList.Items) - { - i++; - if (i > 1) - item.Remove(); - } - } protected override void WndProc(ref Message m) { if (m.Msg == WM_SYSCOMMAND) @@ -208,337 +33,148 @@ namespace SiMay.Net.SessionProviderService switch (m.WParam.ToInt64()) { case IDM_OPTIONS: - AppOptionsDialog dlg = new AppOptionsDialog(); + SystemOptionsDialog dlg = new SystemOptionsDialog(); dlg.ShowDialog(); break; case IDM_RUNLOG: - if (File.Exists("OnRun.log")) + if (File.Exists("Run.log")) { - Process.Start("OnRun.log"); + Process.Start("Run.log"); } break; } } base.WndProc(ref m); } - private void SessionClosed(TcpSocketSaeaSession session) + + private float _uploadTransferBytes; + private float _receiveTransferBytes; + private ImageList _log_imgList; + private int _channelCount = 0; + + private MainSessionProviderService _sessionProviderService; + private void SessionProviderService_Load(object sender, EventArgs e) { - var context = ((TcpSessionChannelContext)session.AppTokens[SysContact.INDEX_CHANNELCONTEXT]); - context.OnClosed(); - context.OnChannelTypeCheckEventHandler -= Context_TcpAwaitnotifyProc; - context.OnManagerChannelMessage -= Context_OnManagerChannelMessage; - context.OnMainChannelMessage -= Context_OnMainChannelMessage; + this.Text = "SiMay中间会话服务-IOASJHD " + System.Reflection.Assembly.GetExecutingAssembly().GetName().Version.ToString(); - _channelContexts.Remove(context); + IntPtr sysMenuHandle = GetSystemMenu(this.Handle, false); - LogShowQueueHelper.WriteLog("有连接断开,工作类型:" + context.ChannelType, "err"); + InsertMenu(sysMenuHandle, 7, MF_SEPARATOR, 0, null); + InsertMenu(sysMenuHandle, 8, MF_BYPOSITION, IDM_OPTIONS, "系统设置"); + InsertMenu(sysMenuHandle, 9, MF_BYPOSITION, IDM_RUNLOG, "运行日志"); - if (context.ChannelType == TcpChannelContextServiceType.ManagerChannel) - { - if (this._managerChannelLoginSign > 0) - Interlocked.Decrement(ref _managerChannelLoginSign); - else - _manager_channel = null; + this._log_imgList = new ImageList(); + this._log_imgList.Images.Add("ok", Resources.ok); + this._log_imgList.Images.Add("err", Resources.erro); + this.logList.SmallImageList = _log_imgList; - } - else if (context.ChannelType == TcpChannelContextServiceType.MainChannel) - { - byte[] data = BitConverter.GetBytes(context.RemoteId); + string localAddress = ApplicationConfiguration.LoalAddress; + int port = ApplicationConfiguration.Port; - if (this._managerChannelLoginSign > 0) - SendMessage(_manager_channel, MessageHelper.CommandCopyTo(MsgCommand.Msg_Close_Session, data)); - } + this.lableIPAddress.Text = localAddress; + this.labelPort.Text = port.ToString(); + this.lableStatrTime.Text = DateTime.Now.ToString(); - if (context.ChannelType != TcpChannelContextServiceType.None) - { - this.RemoveChannelListViewItem(context); - } + this.LaunchService(); } - private void RemoveChannelListViewItem(TcpSessionChannelContext context) + private void LaunchService() { - this.BeginInvoke(new Action(() => + _sessionProviderService = new MainSessionProviderService(); + _sessionProviderService.SynchronizationContext = SynchronizationContext.Current; + _sessionProviderService.OnConnectedEventHandler += OnConnectedEventHandler; + _sessionProviderService.OnClosedEventHandler += OnClosedEventHandler; + _sessionProviderService.LogOutputEventHandler += LogOutputEventHandler; + var startResult = _sessionProviderService.StartService(new StartServiceOptions() { - for (int i = 0; i < this.channelListView.Items.Count; i++) - { - ChannelListViewItem lv = this.channelListView.Items[i] as ChannelListViewItem; - if (lv.TcpChannelContext.Id == context.Id) - { - this.channelListView.Items.RemoveAt(i); - break; - } - } - })); + AccessKey = ApplicationConfiguration.AccessKey, + LocalAddress = ApplicationConfiguration.LoalAddress, + ServicePort = ApplicationConfiguration.Port, + MaxPacketSize = 1024 * 1024 * 2, + MainAppAccessKey = ApplicationConfiguration.MainAppAccessKey, + MainApplicationAllowAccessId = !ApplicationConfiguration.AccessIds.IsNullOrEmpty() ? ApplicationConfiguration.AccessIds.Split(',').Select(c => long.Parse(c)).ToArray() : new long[0], + MainApplicationAnonyMous = ApplicationConfiguration.AnonyMous + }); } - private void AddChannelListViewItem(TcpSessionChannelContext context) - { - this.BeginInvoke(new Action(() => - { - ChannelListViewItem item = new ChannelListViewItem(context); - item.Text = DateTime.Now.ToString(); - item.SubItems.Add(context.ChannelType.ToString()); - item.SubItems.Add("0.00/0.00"); - this.channelListView.Items.Add(item); - })); - } + private void LogOutputEventHandler(LogOutLevelType levelType, string log) => this.Log(levelType, log); - private void Context_TcpAwaitnotifyProc(TcpSessionChannelContext context, TcpChannelContextServiceType type) + private void OnClosedEventHandler(TcpSessionChannelDispatcher dispatcher) { - this.AddChannelListViewItem(context); + ChannelViewItem viewItem = this.channelListView.Items.FristOrDefault(c => c.ChannelDispatcher.Equals(dispatcher)); + this.channelListView.Items.Remove(viewItem); - LogShowQueueHelper.WriteLog("连接被确认,工作类型:" + type.ToString()); - - switch (type) - { - case TcpChannelContextServiceType.MainChannel: - this.MainChannelProcess(context); - break; - case TcpChannelContextServiceType.WorkChannel: - - //通知发起工作连接 - if (this._managerChannelLoginSign > 0) - SendMessage(_manager_channel, MessageHelper.CommandCopyTo(MsgCommand.Msg_Connect_Work)); - else - { - context.Session.Close(true); - } - - break; - case TcpChannelContextServiceType.ManagerChannel: - this.ManagerChannelProcess(context); - break; - case TcpChannelContextServiceType.ManagerWorkChannel: + dispatcher.LogOutputEventHandler -= LogOutputEventHandler; - this.JoinWorkChannelContext(context); - break; - default: - LogShowQueueHelper.WriteLog("未确认的连接:" + type.ToString()); - break; - } + _channelCount--; + lableConnectionCount.Text = _channelCount.ToString(); } - private void MainChannelProcess(TcpSessionChannelContext context) + private void OnConnectedEventHandler(TcpSessionChannelDispatcher dispatcher) { - if (this._managerChannelLoginSign > 0) - { - //发送新上线会话的ID - byte[] data = BitConverter.GetBytes(context.Id); - SendMessage(_manager_channel, MessageHelper.CommandCopyTo(MsgCommand.Msg_Set_Session, data)); - } - - context.OnMainChannelMessage += Context_OnMainChannelMessage; + var viewItem = new ChannelViewItem(dispatcher); + this.channelListView.Items.Add(viewItem); + dispatcher.LogOutputEventHandler += LogOutputEventHandler; + _channelCount++; + lableConnectionCount.Text = _channelCount.ToString(); } - private void ManagerChannelProcess(TcpSessionChannelContext context) - { - //登出管理连接 - if (_managerChannelLoginSign > 0) - { - //close所有mainContext - //while (this._channelContexts.Count < 1) - //{ - // for (int i = 0; i < this._channelContexts.Count; i++) - // { - - // } - // Thread.Sleep(10); - //} - + private void LogOutputEventHandler(DispatcherBase dispatcher, LogOutLevelType levelType, string log) => this.Log(levelType, log); - byte[] body = MessageHelper.CommandCopyTo(MsgCommand.Msg_LogOut); - SendMessage(_manager_channel, body); - LogShowQueueHelper.WriteLog("ManagerChannel LogOut"); - } - - Interlocked.Increment(ref _managerChannelLoginSign); - - if (_manager_channel != null) - { - _manager_channel.OnManagerChannelMessage -= Context_OnManagerChannelMessage; - _manager_channel.OnChannelTypeCheckEventHandler -= Context_TcpAwaitnotifyProc; - } - - _manager_channel = context; - context.OnManagerChannelMessage += Context_OnManagerChannelMessage; - } - - private void Context_OnManagerChannelMessage(TcpSessionChannelContext context, byte[] data) + private void Log(LogOutLevelType levelType, string log) { + var viewItem = new ListViewItem(); - MsgCommand msg = (MsgCommand)data[0]; - switch (msg) + viewItem.Text = DateTime.Now.ToString(); + viewItem.SubItems.Add(log); + switch (levelType) { - case MsgCommand.Msg_Pull_Session: - this.ProcessPullMainChannel(context); - break; - case MsgCommand.Msg_Set_Session_Id: - this.SetSessionId(context, data); - break; - case MsgCommand.Msg_Close_Session: - this.CloseSession(data); + case LogOutLevelType.Debug: + viewItem.ImageKey = "ok"; break; - case MsgCommand.Msg_MessageData: - this.ProcessSendMessage(data); + case LogOutLevelType.Warning: + viewItem.ImageKey = "err"; break; - default: + case LogOutLevelType.Error: + viewItem.ImageKey = "err"; break; } + this.logList.Items.Add(viewItem); + LogHelper.WriteLog($"Level:{levelType.ToString()} {log}", ApplicationConfiguration.LogFileName); } - - private void Context_OnMainChannelMessage(TcpSessionChannelContext context, byte[] data) + private void timerFlowCalac_Tick(object sender, EventArgs e) { - if (this._managerChannelLoginSign == 0) return; - - byte[] bytes = new byte[sizeof(Int64) + data.Length]; - BitConverter.GetBytes(context.RemoteId).CopyTo(bytes, 0); - data.CopyTo(bytes, sizeof(Int64)); - - //MainChannel的数据封装代理协议发送出去 - if (this._managerChannelLoginSign > 0) - SendMessage(_manager_channel, MessageHelper.CommandCopyTo(MsgCommand.Msg_MessageData, bytes)); - } - - private void ProcessSendMessage(byte[] data) - { - //byte[] body = new byte[data.Length - 1]; - //Array.Copy(data, 1, body, 0, body.Length); - - long id = BitConverter.ToInt64(data, 1); - - Console.WriteLine("ProcessSendMessage:" + id); - GCHandle gc = GCHandle.FromIntPtr(new IntPtr(id)); - Console.WriteLine("ProcessSendMessage OK"); - TcpSessionChannelContext context = gc.Target as TcpSessionChannelContext; - - if (context == null) - return; - - //将消息转发给MainChannel - context.SendMessage(data, sizeof(Int64) + 1, data.Length - sizeof(Int64) - 1); - } - - private void CloseSession(byte[] data) - { - long id = BitConverter.ToInt64(data, 1); - Console.WriteLine("CloseSession:" + id); - GCHandle gc = GCHandle.FromIntPtr(new IntPtr(id)); - Console.WriteLine("CloseSession OK"); - TcpSessionChannelContext target_context = gc.Target as TcpSessionChannelContext; - - if (target_context == null) - return; - - target_context.Session.Close(true); - - } - - private void SetSessionId(TcpSessionChannelContext context, byte[] data) - { - byte[] body = new byte[data.Length - 1]; - Array.Copy(data, 1, body, 0, body.Length); - - try + foreach (ChannelViewItem item in channelListView.Items) { - byte[] sessionItems = new byte[sizeof(Int64) * 2]; - for (int i = 0; i < body.Length / (sizeof(Int64) * 2); i++) - { - Array.Copy(body, i * sessionItems.Length, sessionItems, 0, sessionItems.Length); - long id = BitConverter.ToInt64(sessionItems, 0); - - LogShowQueueHelper.WriteLog("DEBUG SetSessionId:" + id); - - GCHandle gc = GCHandle.FromIntPtr(new IntPtr(id)); - - LogShowQueueHelper.WriteLog("DEBUG SetSessionId OK"); - - TcpSessionChannelContext target_context = gc.Target as TcpSessionChannelContext; - id = BitConverter.ToInt64(sessionItems, sizeof(Int64)); - - LogShowQueueHelper.WriteLog("DEBUG SetSessionId RmoteId:" + id); + item.SetVelocityText(item.SendStreamLength, item.ReceiveStreamLength); + _uploadTransferBytes += item.SendStreamLength; + _receiveTransferBytes += item.ReceiveStreamLength; - //关联控制端SessionId - target_context.RemoteId = id; - - byte[] ack = target_context.AckPacketData; - - byte[] ackPack = new byte[ack.Length + sizeof(Int64)]; - BitConverter.GetBytes(id).CopyTo(ackPack, 0); - ack.CopyTo(ackPack, sizeof(Int64)); - - //发送应用层连接确认报(连接密码等信息) - if (this._managerChannelLoginSign > 0) - SendMessage(_manager_channel, MessageHelper.CommandCopyTo(MsgCommand.Msg_MessageData, ackPack)); - } - - if (this._managerChannelLoginSign > 0) - LogShowQueueHelper.WriteLog("Set SessionId SessionCount:" + body.Length / (sizeof(Int64) * 2)); - } - catch (Exception e) - { - LogShowQueueHelper.WriteLog("Set SessionId Exception:" + e.Message, "err"); - } - - - } - private void ProcessPullMainChannel(TcpSessionChannelContext context) - { - //查找所有MainChannel - List contexts = _channelContexts.Where(x => x.ChannelType == TcpChannelContextServiceType.MainChannel).ToList(); - byte[] data = new byte[contexts.Count * sizeof(Int64)]; - for (int i = 0; i < contexts.Count; i++) - { - BitConverter.GetBytes(contexts[i].Id).CopyTo(data, i * sizeof(Int64)); - Console.WriteLine("ProcessPullMainChannel:" + contexts[i].Id); + item.SendStreamLength = 0; + item.ReceiveStreamLength = 0; } - if (_managerChannelLoginSign > 0) - { - SendMessage(_manager_channel, MessageHelper.CommandCopyTo(MsgCommand.Msg_Set_Session, data)); - LogShowQueueHelper.WriteLog("Get Session SessionCount:" + contexts.Count); - } + lbUpload.Text = (_uploadTransferBytes / 1024).ToString("0.00"); + lbReceive.Text = (_receiveTransferBytes / 1024).ToString("0.00"); + _uploadTransferBytes = 0; + _receiveTransferBytes = 0; } - private void JoinWorkChannelContext(TcpSessionChannelContext context) + private void CleanViewLog() { - //查找没有关联过的WorkChannel - TcpSessionChannelContext workContext = _channelContexts.Find(x => x.ChannelType == TcpChannelContextServiceType.WorkChannel && !x.IsJoin); - if (workContext != null) - { - workContext.WorkChannelJoinContext(context.Session, context.GetBuffer); - - //关联完成,释放资源 - context.OnChannelTypeCheckEventHandler -= Context_TcpAwaitnotifyProc; - context.OnClosed(); - - this._channelContexts.Remove(context); - this.RemoveChannelListViewItem(context); - } - else + int i = 0; + foreach (ListViewItem item in logList.Items) { - //没找到就断开连接,回调会释放所有资源 - context.Session.Close(true); + i++; + if (i > 1) + item.Remove(); } } - private void SendMessage(TcpSessionChannelContext context, byte[] data) - { - byte[] body = new byte[sizeof(Int32) + data.Length]; - BitConverter.GetBytes(data.Length).CopyTo(body, 0); - data.CopyTo(body, 4); - - if (context == null) - return; - - context.SendMessage(body, 0, body.Length); - } - private void toolStripMenuItem1_Click(object sender, EventArgs e) { if (logList.SelectedItems.Count != 0) - { - Clipboard.SetText(logList.Items[logList.SelectedItems[0].Index].SubItems[1].Text); - } + Clipboard.SetText(string.Join(",", logList.Items[logList.SelectedItems.FristOrDefault().Index].SubItems.Select(c => c.Text))); } private void toolStripMenuItem2_Click(object sender, EventArgs e) @@ -553,14 +189,13 @@ namespace SiMay.Net.SessionProviderService private void 清空日志ToolStripMenuItem1_Click(object sender, EventArgs e) { - this.Clearlogs(); + this.CleanViewLog(); } private void toolStripMenuItem3_Click(object sender, EventArgs e) { - var channelsListItems = channelListView.SelectedItems; - foreach (ChannelListViewItem item in channelsListItems) - item.TcpChannelContext.Session.Close(true); + foreach (ChannelViewItem item in channelListView.SelectedItems) + item.ChannelDispatcher.CloseSession(); } private void channelListContext_Opening(object sender, CancelEventArgs e) @@ -574,9 +209,7 @@ namespace SiMay.Net.SessionProviderService private void SessionProviderService_FormClosing(object sender, FormClosingEventArgs e) { if (MessageBox.Show("服务正在运行中,确定要关闭吗?", "提示", MessageBoxButtons.OKCancel, MessageBoxIcon.Exclamation) != DialogResult.OK) - { e.Cancel = true; - } } } } diff --git a/SiMay.Net.SessionProviderService/SessionProviderService.resx b/SiMay.Net.SessionProviderService/SessionProviderService.resx index 3f0ca3e..1bfc232 100644 --- a/SiMay.Net.SessionProviderService/SessionProviderService.resx +++ b/SiMay.Net.SessionProviderService/SessionProviderService.resx @@ -126,4 +126,7 @@ 124, 17 + + 530, 24 + \ No newline at end of file diff --git a/SiMay.Net.SessionProviderService/SiMay.Net.SessionProviderService.csproj b/SiMay.Net.SessionProviderService/SiMay.Net.SessionProviderService.csproj index ae880e4..cb082b9 100644 --- a/SiMay.Net.SessionProviderService/SiMay.Net.SessionProviderService.csproj +++ b/SiMay.Net.SessionProviderService/SiMay.Net.SessionProviderService.csproj @@ -8,7 +8,7 @@ WinExe SiMay.Net.SessionProviderService SiMay.Net.SessionProviderService - v4.7.2 + v4.6.1 512 true @@ -50,19 +50,14 @@ - - + Form - - AppOptionsDialog.cs + + SystemOptionsDialog.cs - - - - - + Form @@ -71,11 +66,9 @@ - - - - - AppOptionsDialog.cs + + + SystemOptionsDialog.cs SessionProviderService.cs @@ -108,9 +101,13 @@ {8F2F35CB-D5EE-4D92-B42F-BCFFBF9C9D4F} SiMay.Basic - - {866f8fe0-ee58-4d38-8be7-cbdd19dd1b40} - SiMay.Sockets.Standard + + {0b2b697d-dd20-4869-836c-08c848e1813f} + SiMay.Net.SessionProvider.Core + + + {3c91f949-5187-4cdf-9a5b-aa3c20f7544b} + SiMay.Net.SessionProviderServiceCore diff --git a/SiMay.Net.SessionProviderService/SysContact.cs b/SiMay.Net.SessionProviderService/SysContact.cs deleted file mode 100644 index 47f6bd5..0000000 --- a/SiMay.Net.SessionProviderService/SysContact.cs +++ /dev/null @@ -1,14 +0,0 @@ -using System; -using System.Collections.Generic; -using System.Linq; -using System.Text; -using System.Threading.Tasks; - -namespace SiMay.Net.SessionProviderService -{ - public class SysContact - { - public const int INDEX_CHANNELCONTEXT = 0; - public const int INDEX_CHANNELTYPE = 1; - } -} diff --git a/SiMay.Net.SessionProviderService/AppOptionsDialog.Designer.cs b/SiMay.Net.SessionProviderService/SystemOptionsDialog.Designer.cs similarity index 50% rename from SiMay.Net.SessionProviderService/AppOptionsDialog.Designer.cs rename to SiMay.Net.SessionProviderService/SystemOptionsDialog.Designer.cs index 566c215..e163188 100644 --- a/SiMay.Net.SessionProviderService/AppOptionsDialog.Designer.cs +++ b/SiMay.Net.SessionProviderService/SystemOptionsDialog.Designer.cs @@ -1,6 +1,6 @@ namespace SiMay.Net.SessionProviderService { - partial class AppOptionsDialog + partial class SystemOptionsDialog { /// /// Required designer variable. @@ -41,45 +41,56 @@ this.label6 = new System.Windows.Forms.Label(); this.checkBox1 = new System.Windows.Forms.CheckBox(); this.label7 = new System.Windows.Forms.Label(); + this.txtAccessId = new System.Windows.Forms.TextBox(); + this.label8 = new System.Windows.Forms.Label(); + this.txtMainAppAccessKey = new System.Windows.Forms.TextBox(); + this.label9 = new System.Windows.Forms.Label(); + this.label10 = new System.Windows.Forms.Label(); + this.ckAnonyMous = new System.Windows.Forms.CheckBox(); this.SuspendLayout(); // // label1 // this.label1.AutoSize = true; - this.label1.Location = new System.Drawing.Point(119, 54); + this.label1.Location = new System.Drawing.Point(198, 68); + this.label1.Margin = new System.Windows.Forms.Padding(4, 0, 4, 0); this.label1.Name = "label1"; - this.label1.Size = new System.Drawing.Size(59, 12); + this.label1.Size = new System.Drawing.Size(75, 15); this.label1.TabIndex = 0; this.label1.Text = "监听地址:"; // // txtIPAddress // - this.txtIPAddress.Location = new System.Drawing.Point(184, 51); + this.txtIPAddress.Location = new System.Drawing.Point(284, 64); + this.txtIPAddress.Margin = new System.Windows.Forms.Padding(4); this.txtIPAddress.Name = "txtIPAddress"; - this.txtIPAddress.Size = new System.Drawing.Size(138, 21); + this.txtIPAddress.Size = new System.Drawing.Size(183, 25); this.txtIPAddress.TabIndex = 1; // // txtPort // - this.txtPort.Location = new System.Drawing.Point(184, 79); + this.txtPort.Location = new System.Drawing.Point(284, 99); + this.txtPort.Margin = new System.Windows.Forms.Padding(4); this.txtPort.Name = "txtPort"; - this.txtPort.Size = new System.Drawing.Size(138, 21); + this.txtPort.Size = new System.Drawing.Size(183, 25); this.txtPort.TabIndex = 3; // // label2 // this.label2.AutoSize = true; - this.label2.Location = new System.Drawing.Point(143, 82); + this.label2.Location = new System.Drawing.Point(230, 102); + this.label2.Margin = new System.Windows.Forms.Padding(4, 0, 4, 0); this.label2.Name = "label2"; - this.label2.Size = new System.Drawing.Size(35, 12); + this.label2.Size = new System.Drawing.Size(45, 15); this.label2.TabIndex = 2; this.label2.Text = "端口:"; // // saveBtn // - this.saveBtn.Location = new System.Drawing.Point(232, 216); + this.saveBtn.Location = new System.Drawing.Point(425, 371); + this.saveBtn.Margin = new System.Windows.Forms.Padding(4); this.saveBtn.Name = "saveBtn"; - this.saveBtn.Size = new System.Drawing.Size(90, 36); + this.saveBtn.Size = new System.Drawing.Size(204, 45); this.saveBtn.TabIndex = 4; this.saveBtn.Text = "保存设置"; this.saveBtn.UseVisualStyleBackColor = true; @@ -87,17 +98,19 @@ // // txtBacklog // - this.txtBacklog.Location = new System.Drawing.Point(184, 106); + this.txtBacklog.Location = new System.Drawing.Point(284, 132); + this.txtBacklog.Margin = new System.Windows.Forms.Padding(4); this.txtBacklog.Name = "txtBacklog"; - this.txtBacklog.Size = new System.Drawing.Size(138, 21); + this.txtBacklog.Size = new System.Drawing.Size(183, 25); this.txtBacklog.TabIndex = 6; // // label3 // this.label3.AutoSize = true; - this.label3.Location = new System.Drawing.Point(95, 109); + this.label3.Location = new System.Drawing.Point(166, 136); + this.label3.Margin = new System.Windows.Forms.Padding(4, 0, 4, 0); this.label3.Name = "label3"; - this.label3.Size = new System.Drawing.Size(83, 12); + this.label3.Size = new System.Drawing.Size(105, 15); this.label3.TabIndex = 5; this.label3.Text = "连接挂起队列:"; // @@ -105,9 +118,10 @@ // this.label4.AutoSize = true; this.label4.Font = new System.Drawing.Font("宋体", 9F, System.Drawing.FontStyle.Bold, System.Drawing.GraphicsUnit.Point, ((byte)(134))); - this.label4.Location = new System.Drawing.Point(95, 29); + this.label4.Location = new System.Drawing.Point(166, 36); + this.label4.Margin = new System.Windows.Forms.Padding(4, 0, 4, 0); this.label4.Name = "label4"; - this.label4.Size = new System.Drawing.Size(57, 12); + this.label4.Size = new System.Drawing.Size(71, 15); this.label4.TabIndex = 7; this.label4.Text = "基本设置"; // @@ -115,52 +129,124 @@ // this.label5.AutoSize = true; this.label5.Font = new System.Drawing.Font("宋体", 9F, System.Drawing.FontStyle.Bold, System.Drawing.GraphicsUnit.Point, ((byte)(134))); - this.label5.Location = new System.Drawing.Point(95, 163); + this.label5.Location = new System.Drawing.Point(166, 204); + this.label5.Margin = new System.Windows.Forms.Padding(4, 0, 4, 0); this.label5.Name = "label5"; - this.label5.Size = new System.Drawing.Size(57, 12); + this.label5.Size = new System.Drawing.Size(71, 15); this.label5.TabIndex = 8; this.label5.Text = "访问安全"; // // txtAccessKey // - this.txtAccessKey.Location = new System.Drawing.Point(184, 187); + this.txtAccessKey.Location = new System.Drawing.Point(284, 234); + this.txtAccessKey.Margin = new System.Windows.Forms.Padding(4); this.txtAccessKey.Name = "txtAccessKey"; - this.txtAccessKey.Size = new System.Drawing.Size(138, 21); + this.txtAccessKey.Size = new System.Drawing.Size(183, 25); this.txtAccessKey.TabIndex = 10; // // label6 // this.label6.AutoSize = true; - this.label6.Location = new System.Drawing.Point(113, 190); + this.label6.Location = new System.Drawing.Point(190, 238); + this.label6.Margin = new System.Windows.Forms.Padding(4, 0, 4, 0); this.label6.Name = "label6"; - this.label6.Size = new System.Drawing.Size(65, 12); + this.label6.Size = new System.Drawing.Size(87, 15); this.label6.TabIndex = 9; this.label6.Text = "AccessKey:"; // // checkBox1 // this.checkBox1.AutoSize = true; - this.checkBox1.Location = new System.Drawing.Point(184, 135); + this.checkBox1.Enabled = false; + this.checkBox1.Location = new System.Drawing.Point(284, 169); + this.checkBox1.Margin = new System.Windows.Forms.Padding(4); this.checkBox1.Name = "checkBox1"; - this.checkBox1.Size = new System.Drawing.Size(60, 16); + this.checkBox1.Size = new System.Drawing.Size(74, 19); this.checkBox1.TabIndex = 11; this.checkBox1.Text = "不启动"; this.checkBox1.UseVisualStyleBackColor = true; + this.checkBox1.CheckedChanged += new System.EventHandler(this.checkBox1_CheckedChanged); // // label7 // this.label7.AutoSize = true; - this.label7.Location = new System.Drawing.Point(119, 135); + this.label7.Enabled = false; + this.label7.Location = new System.Drawing.Point(198, 169); + this.label7.Margin = new System.Windows.Forms.Padding(4, 0, 4, 0); this.label7.Name = "label7"; - this.label7.Size = new System.Drawing.Size(59, 12); + this.label7.Size = new System.Drawing.Size(75, 15); this.label7.TabIndex = 12; this.label7.Text = "开机启动:"; // - // AppOptionsDialog + // txtAccessId // - this.AutoScaleDimensions = new System.Drawing.SizeF(6F, 12F); + this.txtAccessId.Location = new System.Drawing.Point(284, 267); + this.txtAccessId.Margin = new System.Windows.Forms.Padding(4); + this.txtAccessId.Name = "txtAccessId"; + this.txtAccessId.Size = new System.Drawing.Size(183, 25); + this.txtAccessId.TabIndex = 14; + // + // label8 + // + this.label8.AutoSize = true; + this.label8.Location = new System.Drawing.Point(198, 270); + this.label8.Margin = new System.Windows.Forms.Padding(4, 0, 4, 0); + this.label8.Name = "label8"; + this.label8.Size = new System.Drawing.Size(79, 15); + this.label8.TabIndex = 13; + this.label8.Text = "AccessId:"; + // + // txtMainAppAccessKey + // + this.txtMainAppAccessKey.Location = new System.Drawing.Point(284, 300); + this.txtMainAppAccessKey.Margin = new System.Windows.Forms.Padding(4); + this.txtMainAppAccessKey.Name = "txtMainAppAccessKey"; + this.txtMainAppAccessKey.Size = new System.Drawing.Size(183, 25); + this.txtMainAppAccessKey.TabIndex = 16; + // + // label9 + // + this.label9.AutoSize = true; + this.label9.Location = new System.Drawing.Point(134, 303); + this.label9.Margin = new System.Windows.Forms.Padding(4, 0, 4, 0); + this.label9.Name = "label9"; + this.label9.Size = new System.Drawing.Size(143, 15); + this.label9.TabIndex = 15; + this.label9.Text = "MainAppAccessKey:"; + // + // label10 + // + this.label10.AutoSize = true; + this.label10.Location = new System.Drawing.Point(202, 341); + this.label10.Margin = new System.Windows.Forms.Padding(4, 0, 4, 0); + this.label10.Name = "label10"; + this.label10.Size = new System.Drawing.Size(75, 15); + this.label10.TabIndex = 18; + this.label10.Text = "匿名登陆:"; + // + // ckAnonyMous + // + this.ckAnonyMous.AutoSize = true; + this.ckAnonyMous.Location = new System.Drawing.Point(284, 340); + this.ckAnonyMous.Margin = new System.Windows.Forms.Padding(4); + this.ckAnonyMous.Name = "ckAnonyMous"; + this.ckAnonyMous.Size = new System.Drawing.Size(74, 19); + this.ckAnonyMous.TabIndex = 17; + this.ckAnonyMous.Text = "不允许"; + this.ckAnonyMous.UseVisualStyleBackColor = true; + this.ckAnonyMous.CheckedChanged += new System.EventHandler(this.ckAnonyMous_CheckedChanged); + // + // SystemOptionsDialog + // + this.AutoScaleDimensions = new System.Drawing.SizeF(8F, 15F); this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font; - this.ClientSize = new System.Drawing.Size(425, 265); + this.ClientSize = new System.Drawing.Size(664, 440); + this.Controls.Add(this.label10); + this.Controls.Add(this.ckAnonyMous); + this.Controls.Add(this.txtMainAppAccessKey); + this.Controls.Add(this.label9); + this.Controls.Add(this.txtAccessId); + this.Controls.Add(this.label8); this.Controls.Add(this.label7); this.Controls.Add(this.checkBox1); this.Controls.Add(this.txtAccessKey); @@ -175,8 +261,9 @@ this.Controls.Add(this.txtIPAddress); this.Controls.Add(this.label1); this.FormBorderStyle = System.Windows.Forms.FormBorderStyle.FixedSingle; + this.Margin = new System.Windows.Forms.Padding(4); this.MaximizeBox = false; - this.Name = "AppOptionsDialog"; + this.Name = "SystemOptionsDialog"; this.StartPosition = System.Windows.Forms.FormStartPosition.CenterScreen; this.Text = "系统设置"; this.Load += new System.EventHandler(this.AppOptions_Load); @@ -200,5 +287,11 @@ private System.Windows.Forms.Label label6; private System.Windows.Forms.CheckBox checkBox1; private System.Windows.Forms.Label label7; + private System.Windows.Forms.TextBox txtAccessId; + private System.Windows.Forms.Label label8; + private System.Windows.Forms.TextBox txtMainAppAccessKey; + private System.Windows.Forms.Label label9; + private System.Windows.Forms.Label label10; + private System.Windows.Forms.CheckBox ckAnonyMous; } } \ No newline at end of file diff --git a/SiMay.Net.SessionProviderService/AppOptionsDialog.cs b/SiMay.Net.SessionProviderService/SystemOptionsDialog.cs similarity index 39% rename from SiMay.Net.SessionProviderService/AppOptionsDialog.cs rename to SiMay.Net.SessionProviderService/SystemOptionsDialog.cs index cce68e9..b3dcb87 100644 --- a/SiMay.Net.SessionProviderService/AppOptionsDialog.cs +++ b/SiMay.Net.SessionProviderService/SystemOptionsDialog.cs @@ -10,9 +10,9 @@ using System.Windows.Forms; namespace SiMay.Net.SessionProviderService { - public partial class AppOptionsDialog : Form + public partial class SystemOptionsDialog : Form { - public AppOptionsDialog() + public SystemOptionsDialog() { InitializeComponent(); } @@ -24,12 +24,13 @@ namespace SiMay.Net.SessionProviderService MessageBox.Show("请完整输入服务器配置信息", "提示", 0, MessageBoxIcon.Exclamation); return; } - ApplicationConfiguration.IPAddress = txtIPAddress.Text; - ApplicationConfiguration.Port = txtPort.Text; - ApplicationConfiguration.Backlog = txtBacklog.Text; - ApplicationConfiguration.ServiceAccessKey = txtAccessKey.Text; - - AccessKeyExamine.ServiceAccessKey = long.Parse(txtAccessKey.Text); + ApplicationConfiguration.LoalAddress = txtIPAddress.Text; + ApplicationConfiguration.Port = int.Parse(txtPort.Text); + ApplicationConfiguration.Backlog = int.Parse(txtBacklog.Text); + ApplicationConfiguration.AccessKey = long.Parse(txtAccessKey.Text); + ApplicationConfiguration.AnonyMous = this.ckAnonyMous.Checked; + ApplicationConfiguration.AccessIds = txtAccessId.Text; + ApplicationConfiguration.MainAppAccessKey = long.Parse(txtMainAppAccessKey.Text); DialogResult result = MessageBox.Show("设置已保存,是否重启程序以生效已保存的应用设置?", "提示", MessageBoxButtons.OKCancel, MessageBoxIcon.Exclamation); @@ -41,10 +42,26 @@ namespace SiMay.Net.SessionProviderService private void AppOptions_Load(object sender, EventArgs e) { - txtIPAddress.Text = ApplicationConfiguration.IPAddress; - txtPort.Text = ApplicationConfiguration.Port; - txtBacklog.Text = ApplicationConfiguration.Backlog; - txtAccessKey.Text = ApplicationConfiguration.ServiceAccessKey; + txtIPAddress.Text = ApplicationConfiguration.LoalAddress; + txtPort.Text = ApplicationConfiguration.Port.ToString(); + txtBacklog.Text = ApplicationConfiguration.Backlog.ToString(); + txtAccessKey.Text = ApplicationConfiguration.AccessKey.ToString(); + txtAccessId.Text = ApplicationConfiguration.AccessIds; + txtMainAppAccessKey.Text = ApplicationConfiguration.MainAppAccessKey.ToString(); + ckAnonyMous.Checked = ApplicationConfiguration.AnonyMous; + + ckAnonyMous.Text = ckAnonyMous.Checked ? "允许" : "不允许"; + checkBox1.Text = checkBox1.Checked ? "开机启动" : "不启动"; + } + + private void ckAnonyMous_CheckedChanged(object sender, EventArgs e) + { + ckAnonyMous.Text = ckAnonyMous.Checked ? "允许" : "不允许"; + } + + private void checkBox1_CheckedChanged(object sender, EventArgs e) + { + checkBox1.Text = checkBox1.Checked ? "开机启动" : "不启动"; } } } diff --git a/SiMay.Net.SessionProviderService/AppOptionsDialog.resx b/SiMay.Net.SessionProviderService/SystemOptionsDialog.resx similarity index 100% rename from SiMay.Net.SessionProviderService/AppOptionsDialog.resx rename to SiMay.Net.SessionProviderService/SystemOptionsDialog.resx diff --git a/SiMay.Net.SessionProviderService/TcpChannelContextServiceType.cs b/SiMay.Net.SessionProviderService/TcpChannelContextServiceType.cs deleted file mode 100644 index c482837..0000000 --- a/SiMay.Net.SessionProviderService/TcpChannelContextServiceType.cs +++ /dev/null @@ -1,17 +0,0 @@ -using System; -using System.Collections.Generic; -using System.Linq; -using System.Text; -using System.Threading.Tasks; - -namespace SiMay.Net.SessionProviderService -{ - public enum TcpChannelContextServiceType - { - MainChannel, - WorkChannel, - ManagerChannel, - ManagerWorkChannel, - None - } -} diff --git a/SiMay.Net.SessionProviderService/TcpSessionChannelContext.cs b/SiMay.Net.SessionProviderService/TcpSessionChannelContext.cs deleted file mode 100644 index 27110bf..0000000 --- a/SiMay.Net.SessionProviderService/TcpSessionChannelContext.cs +++ /dev/null @@ -1,302 +0,0 @@ -using SiMay.Basic; -using SiMay.Net.SessionProvider.Core; -using SiMay.Net.SessionProviderService.Delagate; -using SiMay.Net.SessionProviderService.Notify; -using SiMay.Sockets.Tcp; -using SiMay.Sockets.Tcp.Session; -using System; -using System.Collections.Generic; -using System.Linq; -using System.Runtime.InteropServices; -using System.Text; -using System.Threading.Tasks; - -namespace SiMay.Net.SessionProviderService -{ - public class TcpSessionChannelContext - { - const short AckPacket = 1000; - - /// - /// 关联的会话(通常是主控工作连接) - /// - private TcpSocketSaeaSession _joinSession; - public TcpSocketSaeaSession JoinSession - { - get { return _joinSession; } - } - - /// - /// 通道会话(通常是服务工作连接) - /// - private TcpSocketSaeaSession _session; - public TcpSocketSaeaSession Session - { - get { return _session; } - } - - /// - /// 通道数据缓冲区 - /// - private List _buffer = new List(); - public byte[] GetBuffer - { - get { return this._buffer.ToArray(); } - } - - /// - /// 通道服务类型(主控连接,服务主连接,服务工作连接,主控工作连接) - /// - private TcpChannelContextServiceType _channelType = TcpChannelContextServiceType.None; - public TcpChannelContextServiceType ChannelType - { - get { return _channelType; } - } - - /// - /// 通道是否已与工作连接关联 - /// - private bool _isJoin = false; - public bool IsJoin - { - get { return this._isJoin; } - } - - /// - /// 通道上下文标识 - /// - private long _hasId; - public long Id - { - get { return _hasId; } - } - - /// - /// 代理协议的远程会话上下文标识 - /// - private long _remoteSessionContextId; - public long RemoteId - { - get { return _remoteSessionContextId; } - set { _remoteSessionContextId = value; } - } - - /// - /// 连接后保留的ACK数据包,用于与主控端连接 - /// - byte[] _ack_buffer; - public byte[] AckPacketData - { - get { return _ack_buffer; } - } - - public event TcpChannelContextNotifyHandler OnChannelTypeCheckEventHandler; - - public event TcpChannelContextNotifyHandler OnManagerChannelMessage; - - public event TcpChannelContextNotifyHandler OnMainChannelMessage; - - public TcpSessionChannelContext(TcpSocketSaeaSession session) - { - _session = session; - - //与连接绑定,当消息接收后,会通过OnMessage接收 - session.AppTokens = new object[] - { - this, - TcpChannelContextServiceType.None - }; - - //获取通道对象内存地址作为id - //GCHandle gc = GCHandle.Alloc(this, GCHandleType.WeakTrackResurrection); - this._hasId = this.GetHashCode();//GCHandle.ToIntPtr(gc).ToInt64(); - } - - /// - /// 向通道发送消息 - /// - /// - /// - /// - public void SendMessage(byte[] data, int offset, int lenght) - { - if (this._session == null) - return; - - _session.SendAsync(data, offset, lenght); - } - - /// - /// 向关联同发送消息 - /// - /// - /// - /// - public void SendMessageToJoinSession(byte[] data, int offset, int lenght) - { - if (this._joinSession == null) - return; - - _joinSession.SendAsync(data, offset, lenght); - } - - /// - /// 关联通道 - /// - /// - /// - public void WorkChannelJoinContext(TcpSocketSaeaSession session, byte[] buffer) - { - _joinSession = session; - - session.AppTokens[0] = this; - - //转发给工作连接 - if (buffer.Length > 0) - this._session.SendAsync(buffer); - if (this._buffer.Count > 0) - { - this._joinSession.SendAsync(this._buffer.ToArray()); - this._buffer.Clear(); - } - - this._isJoin = true; - } - - /// - /// 消息处理 - /// - /// - public void OnMessage(TcpSocketSaeaSession session) - { - byte[] data = new byte[session.ReceiveBytesTransferred]; - Array.Copy(session.CompletedBuffer, 0, data, 0, data.Length); - - var type = session.AppTokens[SysContact.INDEX_CHANNELTYPE].ConvertTo(); - if (type == TcpChannelContextServiceType.None) - { - //当通道类型未确认时,进入该区域处理消息 - _buffer.AddRange(data); - if (_buffer.Count < 4) - return; - - byte[] lenBytes = _buffer.GetRange(0, 4).ToArray(); - int packageLen = BitConverter.ToInt32(lenBytes, 0); - - if (packageLen < 0 || packageLen > 1024 * 1024 * 2) - { - session.Close(true); - return; - } - - if (packageLen > _buffer.Count - 4) - return; - - //保留ack,与控制端连接时要用到 - this._ack_buffer = _buffer.GetRange(0, packageLen + 4).ToArray(); - - byte[] Ack = GZipHelper.Decompress(_buffer.GetRange(4, packageLen).ToArray()); - - short headMsg = BitConverter.ToInt16(Ack, 0); - - if (headMsg == AckPacket) - { - // 命令头 消息体 连接类型 - this._channelType = (TcpChannelContextServiceType)Ack[sizeof(Int16) + sizeof(Int64) + sizeof(Byte) - 1]; - - if (this._channelType == TcpChannelContextServiceType.ManagerChannel) - { - long accessKey = BitConverter.ToInt64(Ack, 2); - - if (!AccessKeyExamine.CheckOut(accessKey))//连接密码确认 - { - LogShowQueueHelper.WriteLog("ManagerChannel AccessKey Wrong " + accessKey.ToString(), "err"); - - byte[] body = MessageHelper.CommandCopyTo(MsgCommand.Msg_AccessKeyWrong); - - byte[] pack = new byte[body.Length + sizeof(Int32)]; - BitConverter.GetBytes(body.Length).CopyTo(pack, 0); - body.CopyTo(pack, 4); - - session.SendAsync(pack); - //session.Close(true); - return; - } - } - - this._session.AppTokens[SysContact.INDEX_CHANNELTYPE] = this._channelType; - - if (this._channelType == TcpChannelContextServiceType.ManagerWorkChannel - || this._channelType == TcpChannelContextServiceType.ManagerChannel) - { - _buffer.RemoveRange(0, packageLen + 4); - } - - this.OnChannelTypeCheckEventHandler?.Invoke(this, this._channelType); - - if (this._channelType == TcpChannelContextServiceType.ManagerChannel) - this.ManagerPackageProcess();//如果缓冲区还有数据 - } - else - { - session.Close(true); - } - } - else if (type == TcpChannelContextServiceType.WorkChannel && this._isJoin) - { - if (this._joinSession == null) - return; - - this._joinSession.SendAsync(data); - } - else if (type == TcpChannelContextServiceType.ManagerWorkChannel && this._channelType != type)//当前连接类型为ManagerWorkChannel且当前通道类型为ManagerWorkChannel时表示通道此时未与工作类型关联,暂时将数据存放在缓存区,待关联时再将数据转发 - { - if (this._session == null) - return; - - this._session.SendAsync(data); - } - else if (type == TcpChannelContextServiceType.ManagerChannel) - { - this._buffer.AddRange(data); - this.ManagerPackageProcess(); - } - else if (type == TcpChannelContextServiceType.MainChannel) - { - this.OnMainChannelMessage?.Invoke(this, data);//直接转发 - } - else - { - _buffer.AddRange(data); - } - - } - - private void ManagerPackageProcess() - { - do - { - if (_buffer.Count < 4) - return; - - byte[] lenBytes = _buffer.GetRange(0, 4).ToArray(); - int packageLen = BitConverter.ToInt32(lenBytes, 0); - - if (packageLen > _buffer.Count - 4) - return; - - byte[] completedBytes = _buffer.GetRange(4, packageLen).ToArray(); - - this.OnManagerChannelMessage?.Invoke(this, completedBytes); - - _buffer.RemoveRange(0, packageLen + 4); - - } while (_buffer.Count > 4); - } - public void OnClosed() - { - this._session?.Close(true); - this._joinSession?.Close(true); - } - } -} diff --git a/SiMay.Net.SessionProviderService/Win32.cs b/SiMay.Net.SessionProviderService/Win32.cs new file mode 100644 index 0000000..3cb1116 --- /dev/null +++ b/SiMay.Net.SessionProviderService/Win32.cs @@ -0,0 +1,53 @@ +using System; +using System.Collections.Generic; +using System.Drawing; +using System.Linq; +using System.Runtime.InteropServices; +using System.Text; +using System.Threading.Tasks; + +namespace SiMay.Net.SessionProviderService +{ + public class Win32 + { + public const int WM_SYSCOMMAND = 0x112; + + public const Int32 MF_SEPARATOR = 0x800; + public const Int32 MF_BYPOSITION = 0x400; + public const Int32 MF_STRING = 0x0; + public const Int32 MF_REMOVE = 0x1000; + + public const uint MF_ENABLED = 0; + public const uint MF_DISABLED = (uint)0x00000002L; + public const uint MF_UNCHECKED = 0; + public const uint MF_CHECKED = (uint)0x00000008L; + + [DllImport("user32.dll")] + public static extern IntPtr GetSystemMenu(IntPtr hWnd, bool bRevert);//获取窗体系统菜单 + + [DllImport("user32.dll")] + public static extern bool InsertMenu(IntPtr hMenu, Int32 wPosition, Int32 wFlags, Int32 wIDNewItem, string lpNewItem);//插入菜单 + + [DllImport("user32.dll", CallingConvention = CallingConvention.StdCall)] + public static extern bool RemoveMenu(IntPtr hMenu, uint nPosition, uint nFlags);//删除菜单 + + [DllImport("user32.dll", CallingConvention = CallingConvention.StdCall)] + private static extern bool SetMenuItemBitmaps(IntPtr hMenu, Int32 nPosition, Int32 nFlags, Bitmap pBmpUnchecked, Bitmap pBmpchecked);//设置菜单图片 + + [DllImport("user32.dll", CallingConvention = CallingConvention.StdCall)] + public static extern bool InsertMenuItem(IntPtr hMenu, Int32 uItem, Int32 lpMenuItemInfo, bool fByPos);//插入菜单 + + [DllImport("user32.dll", CallingConvention = CallingConvention.StdCall)] + public static extern bool AppendMenu(IntPtr hMenu, Int32 nFlags, Int32 IDNewItem, string lpNewItem);//追加菜单 + + [DllImport("user32.dll")] + public static extern ulong CheckMenuItem(IntPtr hmenu, uint uIDCheckItem, uint uCheck);//设置菜单勾选 + + [DllImport("user32.dll")] + public static extern bool EnableMenuItem(IntPtr hmenu, uint uIDEnableItem, uint wEnable);//设置菜单可用 + + + [DllImport("User32")] + public static extern bool FlashWindow(IntPtr hWnd, bool bInvert);//任务栏图标闪烁 + } +} diff --git a/SiMay.Net.SessionProviderServiceCore/ApplicationConfiguartion.cs b/SiMay.Net.SessionProviderServiceCore/ApplicationConfiguartion.cs index 5505cf7..5780d5e 100644 --- a/SiMay.Net.SessionProviderServiceCore/ApplicationConfiguartion.cs +++ b/SiMay.Net.SessionProviderServiceCore/ApplicationConfiguartion.cs @@ -4,36 +4,47 @@ using System.Text; namespace SiMay.Net.SessionProviderServiceCore { - public class ApplicationConfiguartion + internal class ApplicationConfiguartion + { + public static void SetOptions(StartServiceOptions options) => Options = options; + public static StartServiceOptions Options { get; private set; } + } + + public class StartServiceOptions { /// /// 监听地址 /// - public static string LocalAddress { get; set; } + public string LocalAddress { get; set; } /// /// 监听端口 /// - public static int ServicePort { get; set; } + public int ServicePort { get; set; } /// /// 最大数据包长度 /// - public static long MaxPacketSize { get; set; } + public long MaxPacketSize { get; set; } /// /// 允许主控端匿名登陆 /// - public static bool MainApplicationAnonymous { get; set; } + public bool MainApplicationAnonyMous { get; set; } /// /// 允许登陆的主控端Id /// - public static long[] MainApplicationAllowAccessId { get; set; } + public long[] MainApplicationAllowAccessId { get; set; } + + /// + /// 主控端登陆Key + /// + public long MainAppAccessKey { get; set; } /// - /// 连接AccessKey(包含主控端) + /// 连接AccessKey /// - public static int AccessKey { get; set; } + public long AccessKey { get; set; } } } diff --git a/SiMay.Net.SessionProviderServiceCore/Dispatcher/ApportionDispatcher.cs b/SiMay.Net.SessionProviderServiceCore/Dispatcher/ApportionDispatcher.cs index b3fa8fc..d1191fb 100644 --- a/SiMay.Net.SessionProviderServiceCore/Dispatcher/ApportionDispatcher.cs +++ b/SiMay.Net.SessionProviderServiceCore/Dispatcher/ApportionDispatcher.cs @@ -17,7 +17,7 @@ namespace SiMay.Net.SessionProviderServiceCore public event Action ApportionTypeHandlerEvent; - private byte[] _ackRetainPacketData; + private byte[] _ackRetainData; private long _accessId; public override void OnMessage() { @@ -28,33 +28,43 @@ namespace SiMay.Net.SessionProviderServiceCore byte[] lenBytes = ListByteBuffer.GetRange(0, defineHeadSize).ToArray(); int packageLen = BitConverter.ToInt32(lenBytes, 0); - if (packageLen < 0 || packageLen > ApplicationConfiguartion.MaxPacketSize || packageLen < 25) //数据不合法 或 小于大概ack固定长度 + if (packageLen < 0 || packageLen > ApplicationConfiguartion.Options.MaxPacketSize || packageLen < 25) //数据不合法 或 小于大概ack固定长度 { this.CloseSession(); + this.Log(LogOutLevelType.Error, $"Type:{ConnectionWorkType.ToString()} 长度不合法!"); return; } - if (packageLen > ListByteBuffer.Count - defineHeadSize) + if (packageLen + defineHeadSize > ListByteBuffer.Count) return; - this._ackRetainPacketData = ListByteBuffer.GetRange(0, defineHeadSize + packageLen).ToArray(); + this._ackRetainData = ListByteBuffer.GetRange(defineHeadSize, packageLen).ToArray(); ListByteBuffer.RemoveRange(0, packageLen + defineHeadSize); - this._accessId = BitConverter.ToInt64(_ackRetainPacketData, defineHeadSize); - var longSize = sizeof(long); - var packageBody = GZipHelper.Decompress(_ackRetainPacketData, defineHeadSize + longSize, _ackRetainPacketData.Length - defineHeadSize - longSize); + var packageBody = GZipHelper.Decompress(_ackRetainData, longSize, _ackRetainData.Length - longSize); var messageHead = TakeMessageHead(packageBody); if (messageHead == ACK_HEAD) { var ack = PacketSerializeHelper.DeserializePacket(TakeMessage(packageBody)); - if (ValidityAccessIdWithKey(ack.Type, ack.AccessId, ack.AccessKey)) - this.ApportionTypeHandlerEvent?.Invoke(this, ack.Type); + + this._accessId = ack.AccessId; + + if (ValidityAccessIdWithKey((ConnectionWorkType)ack.Type, ack.AccessId, ack.AccessKey)) + this.ApportionTypeHandlerEvent?.Invoke(this, (ConnectionWorkType)ack.Type); else + { + var data = MessageHelper.CopyMessageHeadTo(MessageHead.MID_ACCESS_KEY_WRONG); + this.CurrentSession.SendAsync(data.BuilderHeadPacket()); this.CloseSession(); + this.Log(LogOutLevelType.Debug, $"Type:{((ConnectionWorkType)ack.Type).ToString()} AccessId:{ack.AccessId} 或AccessKey:{ack.AccessKey} 验证失败,登陆不成功!"); + } } else + { this.CloseSession(); + this.Log(LogOutLevelType.Warning, $"未知消息,连接被关闭!"); + } } @@ -67,19 +77,13 @@ namespace SiMay.Net.SessionProviderServiceCore /// private bool ValidityAccessIdWithKey(ConnectionWorkType type, long id, long key) { - if (type == ConnectionWorkType.MainApplicationConnection && - ApplicationConfiguartion.MainApplicationAnonymous && - key.Equals(ApplicationConfiguartion.AccessKey)) - return true;//主控端允许匿名Id登陆 - - else if (type == ConnectionWorkType.MainApplicationConnection && - !ApplicationConfiguartion.MainApplicationAnonymous && - ApplicationConfiguartion.MainApplicationAllowAccessId.Contains(id) && - ApplicationConfiguartion.AccessKey.Equals(key)) - return true; + if (type == ConnectionWorkType.MainApplicationConnection && ApplicationConfiguartion.Options.MainApplicationAnonyMous) + return key.Equals(ApplicationConfiguartion.Options.MainAppAccessKey);//主控端允许匿名Id登陆 + else if (type == ConnectionWorkType.MainApplicationConnection && !ApplicationConfiguartion.Options.MainApplicationAnonyMous) + return ApplicationConfiguartion.Options.MainApplicationAllowAccessId.Contains(id) && ApplicationConfiguartion.Options.MainAppAccessKey.Equals(key); else { - return key.Equals(ApplicationConfiguartion.AccessKey);//其他的暂仅验证AccessKey + return key.Equals(ApplicationConfiguartion.Options.AccessKey);//其他的暂仅验证AccessKey } } @@ -89,7 +93,7 @@ namespace SiMay.Net.SessionProviderServiceCore /// public long GetAccessId() { - if (_ackRetainPacketData.IsNull()) + if (_ackRetainData.IsNull()) throw new ArgumentNullException(); return _accessId; @@ -101,10 +105,10 @@ namespace SiMay.Net.SessionProviderServiceCore /// public byte[] GetACKPacketData() { - if (_ackRetainPacketData.IsNull()) + if (_ackRetainData.IsNull()) throw new ArgumentNullException(); - return _ackRetainPacketData; + return _ackRetainData; } private Int16 TakeMessageHead(byte[] data) @@ -121,7 +125,7 @@ namespace SiMay.Net.SessionProviderServiceCore public override void OnClosed() { - + ListByteBuffer.Clear(); } } } diff --git a/SiMay.Net.SessionProviderServiceCore/Dispatcher/TcpSessionApplicationWorkerConnection.cs b/SiMay.Net.SessionProviderServiceCore/Dispatcher/TcpSessionApplicationWorkerConnection.cs index 6e416a1..1b631a3 100644 --- a/SiMay.Net.SessionProviderServiceCore/Dispatcher/TcpSessionApplicationWorkerConnection.cs +++ b/SiMay.Net.SessionProviderServiceCore/Dispatcher/TcpSessionApplicationWorkerConnection.cs @@ -24,6 +24,7 @@ namespace SiMay.Net.SessionProviderServiceCore } public override void OnMessage() { + base.OnMessage(); if (ListByteBuffer.Count > 0) { this._targetConnection.SendTo(ListByteBuffer.ToArray()); @@ -32,6 +33,8 @@ namespace SiMay.Net.SessionProviderServiceCore } public override void OnClosed() { + if (_targetConnection.CurrentSession.State == Sockets.Tcp.TcpSocketConnectionState.Closed) + return; _targetConnection.CloseSession(); ListByteBuffer.Clear(); } diff --git a/SiMay.Net.SessionProviderServiceCore/Dispatcher/TcpSessionMainApplicationConnection.cs b/SiMay.Net.SessionProviderServiceCore/Dispatcher/TcpSessionMainApplicationConnection.cs index 2dd28dd..b095d3a 100644 --- a/SiMay.Net.SessionProviderServiceCore/Dispatcher/TcpSessionMainApplicationConnection.cs +++ b/SiMay.Net.SessionProviderServiceCore/Dispatcher/TcpSessionMainApplicationConnection.cs @@ -9,6 +9,10 @@ namespace SiMay.Net.SessionProviderServiceCore { public class TcpSessionMainApplicationConnection : TcpSessionChannelDispatcher { + private long _createdTime = DateTime.Now.ToFileTime(); + + public long CreatedTime => _createdTime; + public override ConnectionWorkType ConnectionWorkType => ConnectionWorkType.MainApplicationConnection; private readonly IDictionary _dispatchers; @@ -19,6 +23,8 @@ namespace SiMay.Net.SessionProviderServiceCore public override void OnMessage() { + base.OnMessage(); + int defineHeadSize = sizeof(int); do { @@ -28,18 +34,25 @@ namespace SiMay.Net.SessionProviderServiceCore byte[] lenBytes = ListByteBuffer.GetRange(0, defineHeadSize).ToArray(); int packageLen = BitConverter.ToInt32(lenBytes, 0); - if (packageLen > ListByteBuffer.Count + defineHeadSize) + if (packageLen < 0 || packageLen > ApplicationConfiguartion.Options.MaxPacketSize) + { + this.CloseSession(); + this.Log(LogOutLevelType.Error, $"Type:{ConnectionWorkType.ToString()} 长度不合法!"); + return; + } + + if (packageLen + defineHeadSize > ListByteBuffer.Count) return; byte[] data = ListByteBuffer.GetRange(defineHeadSize, packageLen).ToArray(); - this.MessageHandler(data); + this.MessageCompletedHandler(data); ListByteBuffer.RemoveRange(0, packageLen + defineHeadSize); } while (ListByteBuffer.Count > defineHeadSize); } - private void MessageHandler(byte[] data) + private void MessageCompletedHandler(byte[] data) { switch (data.GetMessageHead()) @@ -79,18 +92,28 @@ namespace SiMay.Net.SessionProviderServiceCore SendTo(data); } + /// + /// 构造带长度消息头的数据 + /// + /// + public override void SendTo(byte[] data) + { + base.SendTo(data.BuilderHeadPacket()); + } + private void TranspondMessage(long dispatcherId, byte[] data) { TcpSessionChannelDispatcher dispatcher; if (_dispatchers.TryGetValue(dispatcherId, out dispatcher)) { - dispatcher.SendTo(data);//直接转发 + dispatcher.SendTo(data.BuilderHeadPacket());//直接转发 } + else this.Log(LogOutLevelType.Debug, $"ID:{dispatcherId} 未找到主服务连接!"); } public override void OnClosed() { - + ListByteBuffer.Clear(); } } } diff --git a/SiMay.Net.SessionProviderServiceCore/Dispatcher/TcpSessionMainConnection.cs b/SiMay.Net.SessionProviderServiceCore/Dispatcher/TcpSessionMainConnection.cs index 386acde..cc51009 100644 --- a/SiMay.Net.SessionProviderServiceCore/Dispatcher/TcpSessionMainConnection.cs +++ b/SiMay.Net.SessionProviderServiceCore/Dispatcher/TcpSessionMainConnection.cs @@ -20,10 +20,13 @@ namespace SiMay.Net.SessionProviderServiceCore public byte[] ACKPacketData { get; set; } long? _accessId; + long? _lastChannelCreatedTime; int? _packageLength; int _transpondOffset; public override void OnMessage() { + base.OnMessage(); + int defineHeadSize = sizeof(int); int defineAccessIdSize = sizeof(long); do @@ -39,31 +42,38 @@ namespace SiMay.Net.SessionProviderServiceCore this._transpondOffset = 0; } + var calculateOffsetLength = (_packageLength.Value + defineHeadSize) - _transpondOffset; + if (ListByteBuffer.Count <= calculateOffsetLength) + calculateOffsetLength = ListByteBuffer.Count; + this._transpondOffset += calculateOffsetLength; + if (calculateOffsetLength == 0) + { + this._accessId = null; this._packageLength = null; this._lastChannelCreatedTime = null;continue; + } + var data = ListByteBuffer.GetRange(0, calculateOffsetLength).ToArray(); TcpSessionChannelDispatcher dispatcher; - if (_dispatchers.TryGetValue(_accessId.Value, out dispatcher) || true) + if (_dispatchers.TryGetValue(_accessId.Value, out dispatcher) && dispatcher is TcpSessionMainApplicationConnection mainApplicationConnection) { - var calculateOffsetLength = (_packageLength.Value + defineHeadSize) - _transpondOffset; - if (ListByteBuffer.Count <= calculateOffsetLength) - calculateOffsetLength = ListByteBuffer.Count; - - var data = ListByteBuffer.GetRange(0, calculateOffsetLength).ToArray(); - - dispatcher?.SendTo(MessageHelper.CopyMessageHeadTo(MessageHead.MID_MESSAGE_DATA, - new MessageDataPacket() - { - AccessId = dispatcher.DispatcherId, - DispatcherId = this.DispatcherId, - Data = data - })); + if (!_lastChannelCreatedTime.HasValue) + this._lastChannelCreatedTime = mainApplicationConnection.CreatedTime; - this._transpondOffset += data.Length; - if (_transpondOffset == _packageLength) + //数据包未完整发送完成期间,如果主控端被登出,则剩余的数据不再发送 + if (mainApplicationConnection.CreatedTime == _lastChannelCreatedTime.Value) { - this._accessId = null; this._packageLength = null; + mainApplicationConnection.SendTo(MessageHelper.CopyMessageHeadTo(MessageHead.MID_MESSAGE_DATA, + new MessageDataPacket() + { + AccessId = dispatcher.DispatcherId, + DispatcherId = this.DispatcherId, + Data = data + })); + } + else + { + this.Log(LogOutLevelType.Debug, "原主控端已离线,数据被抛弃!"); } - - ListByteBuffer.RemoveRange(0, calculateOffsetLength); } + ListByteBuffer.RemoveRange(0, calculateOffsetLength); } while (ListByteBuffer.Count > defineHeadSize + defineAccessIdSize); } @@ -78,7 +88,7 @@ namespace SiMay.Net.SessionProviderServiceCore public override void OnClosed() { - + ListByteBuffer.Clear(); } } } diff --git a/SiMay.Net.SessionProviderServiceCore/DispatcherBase/DispatcherBase.cs b/SiMay.Net.SessionProviderServiceCore/DispatcherBase/DispatcherBase.cs index 1985698..f26d5c0 100644 --- a/SiMay.Net.SessionProviderServiceCore/DispatcherBase/DispatcherBase.cs +++ b/SiMay.Net.SessionProviderServiceCore/DispatcherBase/DispatcherBase.cs @@ -7,17 +7,29 @@ namespace SiMay.Net.SessionProviderServiceCore { public abstract class DispatcherBase : IDisposable { + /// + /// 输出日志 + /// + /// + /// + protected void Log(LogOutLevelType logLevel, string log) + => this.LogOutputEventHandler?.Invoke(this, logLevel, log); + + /// + /// 日志输出事件 + /// + public event Action LogOutputEventHandler; + /// /// 当前连接会话 /// - protected TcpSocketSaeaSession CurrentSession + public TcpSocketSaeaSession CurrentSession { get; - set; + protected set; } private long? _dispatcherId; - /// /// Id /// @@ -51,7 +63,7 @@ namespace SiMay.Net.SessionProviderServiceCore /// /// 缓冲区 /// - public List ListByteBuffer + public virtual List ListByteBuffer { get; set; @@ -72,14 +84,6 @@ namespace SiMay.Net.SessionProviderServiceCore }; } - /// - /// 获取当前会话 - /// - public TcpSocketSaeaSession GetCurrentSession() - { - return CurrentSession; - } - /// /// 关闭当前会话 /// diff --git a/SiMay.Net.SessionProviderServiceCore/DispatcherBase/TcpSessionChannelDispatcher.cs b/SiMay.Net.SessionProviderServiceCore/DispatcherBase/TcpSessionChannelDispatcher.cs index dc3e5dd..8ce6b8d 100644 --- a/SiMay.Net.SessionProviderServiceCore/DispatcherBase/TcpSessionChannelDispatcher.cs +++ b/SiMay.Net.SessionProviderServiceCore/DispatcherBase/TcpSessionChannelDispatcher.cs @@ -6,9 +6,25 @@ namespace SiMay.Net.SessionProviderServiceCore { public abstract class TcpSessionChannelDispatcher : DispatcherBase { + /// + /// 接收长度 + /// + public event Action ReceiveStreamLengthEventHandler; + + /// + /// 发送长度 + /// + public event Action SendStreamLengthEventHandler; + + public override void OnMessage() + { + this.ReceiveStreamLengthEventHandler?.Invoke(this, ListByteBuffer.Count); + } + public virtual void SendTo(byte[] data) { - CurrentSession.SendAsync(data); + this.CurrentSession.SendAsync(data); + this.SendStreamLengthEventHandler?.Invoke(this, data.Length); } } } diff --git a/SiMay.Net.SessionProviderServiceCore/Enums/LogOutLevelType.cs b/SiMay.Net.SessionProviderServiceCore/Enums/LogOutLevelType.cs new file mode 100644 index 0000000..88c26d5 --- /dev/null +++ b/SiMay.Net.SessionProviderServiceCore/Enums/LogOutLevelType.cs @@ -0,0 +1,24 @@ +using System; +using System.Collections.Generic; +using System.Text; + +namespace SiMay.Net.SessionProviderServiceCore +{ + public enum LogOutLevelType + { + /// + /// 调试信息 + /// + Debug, + + /// + /// 警告 + /// + Warning, + + /// + /// 异常错误 + /// + Error + } +} diff --git a/SiMay.Net.SessionProviderServiceCore/Extension/CreateDispatcherExtension.cs b/SiMay.Net.SessionProviderServiceCore/Extension/CreateDispatcherExtension.cs index 1902ac3..a8bfbc1 100644 --- a/SiMay.Net.SessionProviderServiceCore/Extension/CreateDispatcherExtension.cs +++ b/SiMay.Net.SessionProviderServiceCore/Extension/CreateDispatcherExtension.cs @@ -12,7 +12,7 @@ namespace SiMay.Net.SessionProviderServiceCore { var mainServiceChannelDispatcher = new TcpSessionMainConnection(dispatchers); mainServiceChannelDispatcher.ACKPacketData = apportionDispatcher.GetACKPacketData(); - mainServiceChannelDispatcher.SetSession(apportionDispatcher.GetCurrentSession()); + mainServiceChannelDispatcher.SetSession(apportionDispatcher.CurrentSession); var bufferData = apportionDispatcher.ListByteBuffer.ToArray(); if (bufferData.Length > 0)//如缓冲区有数据,则处理消息 { @@ -27,7 +27,7 @@ namespace SiMay.Net.SessionProviderServiceCore var accessId = apportionDispatcher.GetAccessId(); var mainappChannelDispatcher = new TcpSessionMainApplicationConnection(dispatchers); mainappChannelDispatcher.DispatcherId = accessId; - mainappChannelDispatcher.SetSession(apportionDispatcher.GetCurrentSession()); + mainappChannelDispatcher.SetSession(apportionDispatcher.CurrentSession); var bufferData = apportionDispatcher.ListByteBuffer.ToArray(); if (bufferData.Length > 0)//如缓冲区有数据,则处理消息 @@ -42,7 +42,7 @@ namespace SiMay.Net.SessionProviderServiceCore { var workerConnection = new TcpSessionApplicationWorkerConnection(); workerConnection.ConnectionWorkType = workType; - workerConnection.SetSession(apportionDispatcher.GetCurrentSession()); + workerConnection.SetSession(apportionDispatcher.CurrentSession); var bufferData = apportionDispatcher.ListByteBuffer.ToArray(); if (bufferData.Length > 0)//如缓冲区有数据,则处理消息 diff --git a/SiMay.Net.SessionProviderServiceCore/MainSessionProviderService.cs b/SiMay.Net.SessionProviderServiceCore/MainSessionProviderService.cs index 2fbebc9..826f16d 100644 --- a/SiMay.Net.SessionProviderServiceCore/MainSessionProviderService.cs +++ b/SiMay.Net.SessionProviderServiceCore/MainSessionProviderService.cs @@ -8,22 +8,39 @@ using System; using System.Collections.Generic; using System.Linq; using System.Net; +using System.Threading; namespace SiMay.Net.SessionProviderServiceCore { public class MainSessionProviderService { - /// /// 日志输出 /// - public event Action LogOutputEventHandler; + public event Action LogOutputEventHandler; + + /// + /// 连接事件 + /// + public event Action OnConnectedEventHandler; + + /// + /// 离线事件 + /// + public event Action OnClosedEventHandler; + + /// + /// 主线程同步上下文 + /// + public SynchronizationContext SynchronizationContext { get; set; } private TcpSocketSaeaServer _tcpSaeaServer; private IList> _appServiceChannels = new List>(); private IDictionary _dispatchers = new Dictionary(); - public bool StartService() + public bool StartService(StartServiceOptions options) { + ApplicationConfiguartion.SetOptions(options); + var serverConfig = new TcpSocketSaeaServerConfiguration(); serverConfig.ReuseAddress = false; serverConfig.KeepAlive = true; @@ -31,40 +48,62 @@ namespace SiMay.Net.SessionProviderServiceCore serverConfig.KeepAliveSpanTime = 1000; serverConfig.PendingConnectionBacklog = 0; - var ipe = new IPEndPoint(IPAddress.Parse(ApplicationConfiguartion.LocalAddress), ApplicationConfiguartion.ServicePort); + var ipe = new IPEndPoint(IPAddress.Parse(ApplicationConfiguartion.Options.LocalAddress), ApplicationConfiguartion.Options.ServicePort); _tcpSaeaServer = TcpSocketsFactory.CreateServerAgent(TcpSocketSaeaSessionType.Full, serverConfig, (notify, session) => { - switch (notify) + if (SynchronizationContext.IsNull()) + NotifyProc(null); + else + SynchronizationContext.Send(NotifyProc, null); + + void NotifyProc(object @object) { - case TcpSocketCompletionNotify.OnConnected: - - ApportionDispatcher apportionDispatcher = new ApportionDispatcher(); - apportionDispatcher.ApportionTypeHandlerEvent += ApportionTypeHandlerEvent; - apportionDispatcher.SetSession(session); - - break; - case TcpSocketCompletionNotify.OnSend: - break; - case TcpSocketCompletionNotify.OnDataReceiveing: - this.OnDataReceiveingHandler(session); - break; - case TcpSocketCompletionNotify.OnClosed: - this.OnClosedHandler(session); - break; - default: - break; - } + switch (notify) + { + case TcpSessionNotify.OnConnected: + + ApportionDispatcher apportionDispatcher = new ApportionDispatcher(); + apportionDispatcher.ApportionTypeHandlerEvent += ApportionTypeHandlerEvent; + apportionDispatcher.LogOutputEventHandler += ApportionDispatcher_LogOutputEventHandler; + apportionDispatcher.SetSession(session); + break; + case TcpSessionNotify.OnSend: + break; + case TcpSessionNotify.OnDataReceiveing: + this.OnDataReceiveingHandler(session); + break; + case TcpSessionNotify.OnClosed: + this.OnClosedHandler(session); + break; + default: + break; + } + } }); - return true; + + try + { + _tcpSaeaServer.Listen(ipe); + LogOutputEventHandler?.Invoke(LogOutLevelType.Debug, $"SiMay中间会话服务器监听 {ipe.Port} 端口启动成功!"); + return true; + } + catch (Exception ex) + { + LogOutputEventHandler?.Invoke(LogOutLevelType.Error, $"SiMay中间会话服务器启动发生错误,端口:{ipe.Port} 错误信息:{ex.Message}!"); + return false; + } } - private void OnDataReceiveingHandler(TcpSocketSaeaSession session) + private void ApportionDispatcher_LogOutputEventHandler(DispatcherBase dispatcher, LogOutLevelType level, string log) { - byte[] data = new byte[session.ReceiveBytesTransferred]; - Array.Copy(session.CompletedBuffer, 0, data, 0, data.Length); + LogOutputEventHandler?.Invoke(level, log); + } + private void OnDataReceiveingHandler(TcpSocketSaeaSession session) + { + byte[] data = session.CompletedBuffer.Copy(0, session.ReceiveBytesTransferred); var dispatcher = session.AppTokens[SysContanct.INDEX_WORKER].ConvertTo(); dispatcher.ListByteBuffer.AddRange(data); dispatcher.OnMessage(); @@ -96,6 +135,11 @@ namespace SiMay.Net.SessionProviderServiceCore if (_dispatchers.ContainsKey(closedDispatcher.DispatcherId)) _dispatchers.Remove(closedDispatcher.DispatcherId); + + if (closedDispatcher is TcpSessionChannelDispatcher tcpSessionChannelDispatcher) + this.OnClosedEventHandler?.Invoke(tcpSessionChannelDispatcher); + + this.LogOutputEventHandler?.Invoke(LogOutLevelType.Warning, $"ID:{closedDispatcher.DispatcherId} 的连接已与服务器断开连接!"); } private void ApportionTypeHandlerEvent(ApportionDispatcher apportionDispatcher, ConnectionWorkType type) @@ -119,6 +163,7 @@ namespace SiMay.Net.SessionProviderServiceCore default: break; } + this.LogOutputEventHandler?.Invoke(LogOutLevelType.Debug, $"工作类型:{type.ToString()} 的连接已分配!"); } private void MainServiceConnect(ApportionDispatcher apportionDispatcher) @@ -142,6 +187,7 @@ namespace SiMay.Net.SessionProviderServiceCore .Where(c => c.ConnectionWorkType == ConnectionWorkType.MainApplicationConnection) .ForEach(c => c.SendTo(data)); + this.OnConnectedEventHandler?.Invoke(mainServiceChannelDispatcher); _dispatchers.Add(mainServiceChannelDispatcher.DispatcherId, mainServiceChannelDispatcher); } @@ -149,56 +195,70 @@ namespace SiMay.Net.SessionProviderServiceCore { var accessId = apportionDispatcher.GetAccessId(); var mainappChannelDispatcher = apportionDispatcher.CreateMainApplicationChannelDispatcher(_dispatchers); - if (!_dispatchers.ContainsKey(accessId))//可能重连太快 - { - //主控端使用自身AccessId作索引 - _dispatchers.Add(accessId, mainappChannelDispatcher); - } - else + if (_dispatchers.ContainsKey(accessId))//可能重连太快 { var aboutOfCloseDispatcher = _dispatchers[accessId]; var data = MessageHelper.CopyMessageHeadTo(MessageHead.MID_LOGOUT, new LogOutPacket() { - Message = "已有相同Id的主控端登陆,你已被登出!" + Message = "已有相同Id的主控端登陆,你已被登出" }); aboutOfCloseDispatcher.SendTo(data); - aboutOfCloseDispatcher.CloseSession(); + aboutOfCloseDispatcher.CloseSession();//调用后底层会触发Closed事件 + + this.LogOutputEventHandler?.Invoke(LogOutLevelType.Debug, $"有相同Id:{accessId}的主控端登陆!"); } + _dispatchers.Add(accessId, mainappChannelDispatcher); + + this.OnConnectedEventHandler?.Invoke(mainappChannelDispatcher); } private void ApplicationServiceConnect(ApportionDispatcher apportionDispatcher) { + var appWorkerConnectionDispatcher = apportionDispatcher.CreateApplicationWorkerChannelDispatcher(_dispatchers, ConnectionWorkType.ApplicationServiceConnection); + appWorkerConnectionDispatcher.ListByteBuffer.AddRange(apportionDispatcher.GetACKPacketData().BuilderHeadPacket()); + this._dispatchers.Add(appWorkerConnectionDispatcher.DispatcherId, appWorkerConnectionDispatcher); + this._appServiceChannels.Add(new Tuple(apportionDispatcher.GetAccessId(), appWorkerConnectionDispatcher.DispatcherId)); + this.OnConnectedEventHandler?.Invoke(appWorkerConnectionDispatcher); //找到相应主控端连接 TcpSessionChannelDispatcher dispatcher; if (_dispatchers.TryGetValue(apportionDispatcher.GetAccessId(), out dispatcher)) { - var appWorkerConnectionDispatcher = apportionDispatcher.CreateApplicationWorkerChannelDispatcher(_dispatchers, ConnectionWorkType.ApplicationServiceConnection); - this._appServiceChannels.Add(new Tuple(apportionDispatcher.GetAccessId(), appWorkerConnectionDispatcher.DispatcherId)); - var data = MessageHelper.CopyMessageHeadTo(MessageHead.MID_APPWORK); dispatcher.SendTo(data); } + else + { + appWorkerConnectionDispatcher.CloseSession(); + this.LogOutputEventHandler?.Invoke(LogOutLevelType.Debug, $"应用服务工作连接未找到相应的主控端!"); + } } private void ApplicationConnect(ApportionDispatcher apportionDispatcher) { - TcpSessionChannelDispatcher dispatcher; + TcpSessionChannelDispatcher dispatcher = null; var serviceWorkerChannelItem = this._appServiceChannels.FirstOrDefault(c => c.Item1 == apportionDispatcher.GetAccessId()); if (!serviceWorkerChannelItem.IsNull() && _dispatchers.TryGetValue(serviceWorkerChannelItem.Item2, out dispatcher)) { + this._appServiceChannels.Remove(serviceWorkerChannelItem); var serviceChannelDispatcher = dispatcher.ConvertTo(); var appChannelDispatcher = apportionDispatcher.CreateApplicationWorkerChannelDispatcher(_dispatchers, ConnectionWorkType.ApplicationConnection); + this._dispatchers.Add(appChannelDispatcher.DispatcherId, appChannelDispatcher); + this.OnConnectedEventHandler?.Invoke(appChannelDispatcher); + if (!serviceChannelDispatcher.IsJoin) { serviceChannelDispatcher.Join(appChannelDispatcher); serviceChannelDispatcher.OnMessage(); appChannelDispatcher.OnMessage(); } - this._appServiceChannels.Remove(serviceWorkerChannelItem); - - _dispatchers.Add(appChannelDispatcher.DispatcherId, appChannelDispatcher); + else appChannelDispatcher.CloseSession(); + } + else + { + apportionDispatcher.CloseSession(); + this.LogOutputEventHandler?.Invoke(LogOutLevelType.Debug, $"主控端应用工作连接未找到可匹配的应用服务工作连接!"); } } } diff --git a/SiMay.RemoteClient.NewCore/MainService/MainService.cs b/SiMay.RemoteClient.NewCore/MainService/MainService.cs index dba6578..1802e21 100644 --- a/SiMay.RemoteClient.NewCore/MainService/MainService.cs +++ b/SiMay.RemoteClient.NewCore/MainService/MainService.cs @@ -49,7 +49,7 @@ namespace SiMay.ServiceCore.MainService { while (true) //第一次解析域名,直至解析成功 { - var ip = IPHelper.GetHostByName(startParameter.Host); + var ip = HostHelper.GetHostByName(startParameter.Host); if (ip != null) { AppConfiguartion.ServerIPEndPoint = new IPEndPoint(IPAddress.Parse(ip), startParameter.Port); @@ -150,7 +150,7 @@ namespace SiMay.ServiceCore.MainService //尝试解析出最新的域名地址 ThreadHelper.ThreadPoolStart(c => { - var ip = IPHelper.GetHostByName(AppConfiguartion.HostAddress); + var ip = HostHelper.GetHostByName(AppConfiguartion.HostAddress); if (ip.IsNullOrEmpty()) return; AppConfiguartion.ServerIPEndPoint = new IPEndPoint(IPAddress.Parse(ip), AppConfiguartion.HostPort); @@ -163,14 +163,14 @@ namespace SiMay.ServiceCore.MainService /// 作用:连接确认,以便服务端识别这是一个有效的工作连接,type = 中间服务器识别 , accessId = 发起创建应用服务请求的主控端标识 /// /// - private void SendAckPack(TcpSocketSaeaSession session, ConnectionWorkType type, long accessId) + private void SendACK(TcpSocketSaeaSession session, ConnectionWorkType type, long accessId) { SendTo(session, MessageHead.C_GLOBAL_CONNECT, new AckPack() { AccessId = accessId,//当前主控端标识 AccessKey = AppConfiguartion.AccessKey, - Type = type + Type = (byte)type }); } @@ -179,18 +179,18 @@ namespace SiMay.ServiceCore.MainService /// /// /// - public void Notify(TcpSocketCompletionNotify notify, TcpSocketSaeaSession session) + public void Notify(TcpSessionNotify notify, TcpSocketSaeaSession session) { try { switch (notify) { - case TcpSocketCompletionNotify.OnConnected: + case TcpSessionNotify.OnConnected: this.ConnectedHandler(session, notify); break; - case TcpSocketCompletionNotify.OnDataReceiveing: + case TcpSessionNotify.OnDataReceiveing: break; - case TcpSocketCompletionNotify.OnDataReceived: + case TcpSessionNotify.OnDataReceived: var workType = (ConnectionWorkType)session.AppTokens[0]; if (workType == ConnectionWorkType.MAINCON) this.HandlerBinder.InvokePacketHandler(session, GetMessageHead(session), this); @@ -200,7 +200,7 @@ namespace SiMay.ServiceCore.MainService appService.HandlerBinder.InvokePacketHandler(session, GetMessageHead(session), appService); } break; - case TcpSocketCompletionNotify.OnClosed: + case TcpSessionNotify.OnClosed: this.CloseHandler(session, notify); break; } @@ -224,7 +224,7 @@ namespace SiMay.ServiceCore.MainService /// /// /// - private void ConnectedHandler(TcpSocketSaeaSession session, TcpSocketCompletionNotify notify) + private void ConnectedHandler(TcpSocketSaeaSession session, TcpSessionNotify notify) { //当服务主连接离线或未连接,优先与session关联 if (Interlocked.Exchange(ref _sessionKeepSign, STATE_NORMAL) == STATE_DISCONNECT) @@ -236,7 +236,7 @@ namespace SiMay.ServiceCore.MainService }; this.SetSession(session); //服务主连接accessId保留 - this.SendAckPack(session, ConnectionWorkType.MAINCON, 0); + this.SendACK(session, ConnectionWorkType.MAINCON, 0); } else { @@ -253,11 +253,11 @@ namespace SiMay.ServiceCore.MainService service }; service.SetSession(session); - this.SendAckPack(session, ConnectionWorkType.WORKCON, service.AccessId); + this.SendACK(session, ConnectionWorkType.WORKCON, service.AccessId); } } - private void CloseHandler(TcpSocketSaeaSession session, TcpSocketCompletionNotify notify) + private void CloseHandler(TcpSocketSaeaSession session, TcpSessionNotify notify) { if (_sessionKeepSign == STATE_DISCONNECT && session.AppTokens.IsNull()) { @@ -270,7 +270,7 @@ namespace SiMay.ServiceCore.MainService } else if (_sessionKeepSign == STATE_NORMAL && session.AppTokens.IsNull())//task连接,连接服务器失败 { - _taskQueue.Dequeue();//移除 + _taskQueue.Dequeue(); return;//不重试连接,因为可能会连接不上,导致频繁重试连接 } @@ -468,7 +468,7 @@ namespace SiMay.ServiceCore.MainService { var isConstraint = GetMessage(session)[0]; AppConfiguartion.IsOpenScreenView = true; - if (_screenViewIsAction != true || isConstraint == 0) + if (!_screenViewIsAction || isConstraint == 0) this.OnRemoteCreateDesktopView(); } @@ -479,8 +479,10 @@ namespace SiMay.ServiceCore.MainService [PacketHandler(MessageHead.S_MAIN_DESKTOPVIEW_GETFRAME)] private void SendNextFrameDesktopView(TcpSocketSaeaSession session) { - ThreadPool.QueueUserWorkItem(c => + ThreadHelper.ThreadPoolStart(c => { + ThreadLocalAccessId.Value = GetAccessId(session); + var getframe = GetMessageEntity(session); if (getframe.Width == 0 || getframe.Height == 0 || getframe.TimeSpan == 0 || getframe.TimeSpan < 50) return; diff --git a/SiMay.RemoteClient.NewCore/Program.cs b/SiMay.RemoteClient.NewCore/Program.cs index 0b41f68..1eacf96 100644 --- a/SiMay.RemoteClient.NewCore/Program.cs +++ b/SiMay.RemoteClient.NewCore/Program.cs @@ -70,18 +70,18 @@ namespace SiMay.ServiceCore { var startParameter = new StartParameterEx() { - Host = "127.0.0.1", - Port = 5200, + Host = "94.191.115.121", + Port = 522, //Port = 522, GroupName = "默认分组", RemarkInformation = "SiMayService", IsHide = false, IsMutex = false, IsAutoStart = false, - SessionMode = 0, - //SessionMode = 1, + //SessionMode = 0, + SessionMode = 1, AccessKey = 5200, - ServiceVersion = "正式5.0", + ServiceVersion = "正式6.0", RunTimeText = DateTime.Now.ToString(), UniqueId = "AAAAAAAAAAAAAAA11111111", ServiceName = "SiMayService", diff --git a/SiMay.RemoteClient.NewCore/ServiceBase/ApplicationProtocolService.cs b/SiMay.RemoteClient.NewCore/ServiceBase/ApplicationProtocolService.cs index e2e1012..c88e06b 100644 --- a/SiMay.RemoteClient.NewCore/ServiceBase/ApplicationProtocolService.cs +++ b/SiMay.RemoteClient.NewCore/ServiceBase/ApplicationProtocolService.cs @@ -3,6 +3,7 @@ using SiMay.Core; using SiMay.Core.PacketModelBinding; using SiMay.Sockets.Tcp.Session; using System; +using System.Threading; namespace SiMay.ServiceCore { @@ -11,6 +12,7 @@ namespace SiMay.ServiceCore /// public abstract class ApplicationProtocolService : ApplicationServiceBase { + protected ThreadLocal ThreadLocalAccessId = new ThreadLocal(); /// /// 数据处理绑定 /// @@ -40,7 +42,8 @@ namespace SiMay.ServiceCore protected virtual void SendToBefore(TcpSocketSaeaSession session, byte[] data) { - var accessId = GetAccessId(session); + var accessId = ThreadLocalAccessId.IsValueCreated ? ThreadLocalAccessId.Value : GetAccessId(session); + Console.WriteLine("ID:" + accessId); SendTo(session, WrapAccessId(GZipHelper.Compress(data, 0, data.Length), accessId)); } diff --git a/SiMay.RemoteClient.NewCore/TrunkService/Service.cs b/SiMay.RemoteClient.NewCore/TrunkService/Service.cs index af23f32..4cc06ed 100644 --- a/SiMay.RemoteClient.NewCore/TrunkService/Service.cs +++ b/SiMay.RemoteClient.NewCore/TrunkService/Service.cs @@ -49,17 +49,17 @@ namespace SiMay.ServiceCore { switch (notity) { - case TcpSocketCompletionNotify.OnConnected: + case TcpSessionNotify.OnConnected: LogHelper.DebugWriteLog("OnConnected"); break; - case TcpSocketCompletionNotify.OnSend: + case TcpSessionNotify.OnSend: break; - case TcpSocketCompletionNotify.OnDataReceiveing: + case TcpSessionNotify.OnDataReceiveing: break; - case TcpSocketCompletionNotify.OnDataReceived: + case TcpSessionNotify.OnDataReceived: _handlerBinder.InvokePacketHandler(session, session.CompletedBuffer.GetMessageHead(), this); break; - case TcpSocketCompletionNotify.OnClosed: + case TcpSessionNotify.OnClosed: this.SessionClosedHandler(session); break; default: diff --git a/SiMay.RemoteClient.NewCore/TrunkService/UserTrunkContext.cs b/SiMay.RemoteClient.NewCore/TrunkService/UserTrunkContext.cs index f775f3d..93e2ad2 100644 --- a/SiMay.RemoteClient.NewCore/TrunkService/UserTrunkContext.cs +++ b/SiMay.RemoteClient.NewCore/TrunkService/UserTrunkContext.cs @@ -66,19 +66,19 @@ namespace SiMay.ServiceCore { switch (notity) { - case TcpSocketCompletionNotify.OnConnected: + case TcpSessionNotify.OnConnected: LogHelper.DebugWriteLog("InitConntectTrunkService:OnClosed"); _trunkTcpSession = session; SendActiveFlag(); break; - case TcpSocketCompletionNotify.OnSend: + case TcpSessionNotify.OnSend: break; - case TcpSocketCompletionNotify.OnDataReceiveing: + case TcpSessionNotify.OnDataReceiveing: break; - case TcpSocketCompletionNotify.OnDataReceived: + case TcpSessionNotify.OnDataReceived: _handlerBinder.InvokePacketHandler(session, session.CompletedBuffer.GetMessageHead(), this); break; - case TcpSocketCompletionNotify.OnClosed: + case TcpSessionNotify.OnClosed: LogHelper.DebugWriteLog("InitConntectTrunkService:OnClosed"); _trunkTcpSession = null; _autoReset.Set(); diff --git a/SiMay.RemoteControlsCore/AdapterHandlerBase/ApplicationAdapterHandler.cs b/SiMay.RemoteControlsCore/AdapterHandlerBase/ApplicationAdapterHandler.cs index cabe2e1..a5d9398 100644 --- a/SiMay.RemoteControlsCore/AdapterHandlerBase/ApplicationAdapterHandler.cs +++ b/SiMay.RemoteControlsCore/AdapterHandlerBase/ApplicationAdapterHandler.cs @@ -1,6 +1,6 @@ using SiMay.Core; using SiMay.Core.PacketModelBinding; -using SiMay.Net.SessionProvider.SessionBased; +using SiMay.Net.SessionProvider; using System; using System.Collections.Generic; using System.Linq; diff --git a/SiMay.RemoteControlsCore/AdapterHandlerBase/ApplicationProtocolAdapterHandler.cs b/SiMay.RemoteControlsCore/AdapterHandlerBase/ApplicationProtocolAdapterHandler.cs index 96eb0d7..1ab849e 100644 --- a/SiMay.RemoteControlsCore/AdapterHandlerBase/ApplicationProtocolAdapterHandler.cs +++ b/SiMay.RemoteControlsCore/AdapterHandlerBase/ApplicationProtocolAdapterHandler.cs @@ -1,7 +1,7 @@ using SiMay.Basic; using SiMay.Core; using SiMay.Core.PacketModelBinding; -using SiMay.Net.SessionProvider.SessionBased; +using SiMay.Net.SessionProvider; using System; using System.Collections.Generic; using System.Linq; @@ -55,7 +55,7 @@ namespace SiMay.RemoteControlsCore } protected virtual void SendToBefore(SessionProviderContext session, byte[] data) { - var accessId = AppConfiguration.AccessId; + var accessId = AppConfiguration.UseAccessId; SendTo(session, WrapAccessId(GZipHelper.Compress(data, 0, data.Length), accessId)); } diff --git a/SiMay.RemoteControlsCore/AdapterHandlerBase/MainApplicationAdapterHandler.cs b/SiMay.RemoteControlsCore/AdapterHandlerBase/MainApplicationAdapterHandler.cs index d777976..6a404cb 100644 --- a/SiMay.RemoteControlsCore/AdapterHandlerBase/MainApplicationAdapterHandler.cs +++ b/SiMay.RemoteControlsCore/AdapterHandlerBase/MainApplicationAdapterHandler.cs @@ -1,7 +1,7 @@ using SiMay.Basic; using SiMay.Core; using SiMay.Core.Packets; -using SiMay.Net.SessionProvider.SessionBased; +using SiMay.Net.SessionProvider; using System; using System.Collections.Generic; using System.Linq; diff --git a/SiMay.RemoteControlsCore/AppConfiguration.cs b/SiMay.RemoteControlsCore/AppConfiguration.cs index 1698021..4625f25 100644 --- a/SiMay.RemoteControlsCore/AppConfiguration.cs +++ b/SiMay.RemoteControlsCore/AppConfiguration.cs @@ -26,13 +26,16 @@ namespace SiMay.RemoteControlsCore { "AudioBitsPerSample", "16" }, { "AudioChannels", "1" }, { "SessionMode", "0" }, - { "AccessKey", "522222" }, { "ServiceIPAddress", "127.0.0.1" }, { "ServicePort", "522" }, { "EnabledCarousel", "true" }, { "CarouselInterval", "5000" }, { "ViewColumn", "4" }, { "ViewRow", "3" }, + { "EnabledAnonyMous", "true" }, + { "AccessId" , "123456789" }, + { "MainAppAccessKey", "5200" }, + { "AccessKey", "5200" } }; string _filePath = Path.Combine(Environment.CurrentDirectory, "SiMayConfig.ini"); @@ -61,12 +64,6 @@ namespace SiMay.RemoteControlsCore public static AbstractAppConfigBase SysConfig { get; } = new ManagerAppConfig(); - public static long AccessId - { - get; - set; - } - public static string IPAddress { get { return SysConfig.GetConfig("IPAddress"); } @@ -190,5 +187,28 @@ namespace SiMay.RemoteControlsCore get { return int.Parse(SysConfig.GetConfig("ViewRow")); } set { SysConfig.SetConfig("ViewRow", value.ToString()); } } + + /// + /// 临时Id + /// + public static long UseAccessId { get; set; } + + public static long AccessId + { + get { return long.Parse(SysConfig.GetConfig("AccessId")); } + set { SysConfig.SetConfig("AccessId", value.ToString()); } + } + + public static long MainAppAccessKey + { + get { return long.Parse(SysConfig.GetConfig("MainAppAccessKey")); } + set { SysConfig.SetConfig("MainAppAccessKey", value.ToString()); } + } + + public static bool EnabledAnonyMous + { + get { return bool.Parse(SysConfig.GetConfig("EnabledAnonyMous")); } + set { SysConfig.SetConfig("EnabledAnonyMous", value.ToString()); } + } } } \ No newline at end of file diff --git a/SiMay.RemoteControlsCore/ApplicationAdapterHandler/AudioAdapterHandler.cs b/SiMay.RemoteControlsCore/ApplicationAdapterHandler/AudioAdapterHandler.cs index 4d17f7a..2af9960 100644 --- a/SiMay.RemoteControlsCore/ApplicationAdapterHandler/AudioAdapterHandler.cs +++ b/SiMay.RemoteControlsCore/ApplicationAdapterHandler/AudioAdapterHandler.cs @@ -7,7 +7,7 @@ using SiMay.Core; using SiMay.Core.PacketModelBinder.Attributes; using SiMay.Core.PacketModelBinding; using SiMay.Core.Packets; -using SiMay.Net.SessionProvider.SessionBased; +using SiMay.Net.SessionProvider; namespace SiMay.RemoteControlsCore.HandlerAdapters { diff --git a/SiMay.RemoteControlsCore/ApplicationAdapterHandler/KeyboardAdapterHandler.cs b/SiMay.RemoteControlsCore/ApplicationAdapterHandler/KeyboardAdapterHandler.cs index 781aa28..12e6ec6 100644 --- a/SiMay.RemoteControlsCore/ApplicationAdapterHandler/KeyboardAdapterHandler.cs +++ b/SiMay.RemoteControlsCore/ApplicationAdapterHandler/KeyboardAdapterHandler.cs @@ -7,7 +7,7 @@ using SiMay.Core; using SiMay.Core.Extensions; using SiMay.Core.PacketModelBinder.Attributes; using SiMay.Core.PacketModelBinding; -using SiMay.Net.SessionProvider.SessionBased; +using SiMay.Net.SessionProvider; namespace SiMay.RemoteControlsCore.HandlerAdapters { diff --git a/SiMay.RemoteControlsCore/ApplicationAdapterHandler/RegistryEditorAdapterHandler.cs b/SiMay.RemoteControlsCore/ApplicationAdapterHandler/RegistryEditorAdapterHandler.cs index 4fb6b71..0b9f259 100644 --- a/SiMay.RemoteControlsCore/ApplicationAdapterHandler/RegistryEditorAdapterHandler.cs +++ b/SiMay.RemoteControlsCore/ApplicationAdapterHandler/RegistryEditorAdapterHandler.cs @@ -3,7 +3,7 @@ using SiMay.Core; using SiMay.Core.PacketModelBinder.Attributes; using SiMay.Core.PacketModelBinding; using SiMay.Core.Packets.RegEdit; -using SiMay.Net.SessionProvider.SessionBased; +using SiMay.Net.SessionProvider; namespace SiMay.RemoteControlsCore.HandlerAdapters { diff --git a/SiMay.RemoteControlsCore/ApplicationAdapterHandler/RemoteFileAdapterHandler.cs b/SiMay.RemoteControlsCore/ApplicationAdapterHandler/RemoteFileAdapterHandler.cs index 8a6b7a0..478a8cf 100644 --- a/SiMay.RemoteControlsCore/ApplicationAdapterHandler/RemoteFileAdapterHandler.cs +++ b/SiMay.RemoteControlsCore/ApplicationAdapterHandler/RemoteFileAdapterHandler.cs @@ -10,7 +10,7 @@ using SiMay.Core; using SiMay.Core.PacketModelBinder.Attributes; using SiMay.Core.Packets; using SiMay.Core.Packets.FileManager; -using SiMay.Net.SessionProvider.SessionBased; +using SiMay.Net.SessionProvider; using SiMay.Serialize.Standard; namespace SiMay.RemoteControlsCore.HandlerAdapters diff --git a/SiMay.RemoteControlsCore/ApplicationAdapterHandler/RemoteScreenAdapterHandler.cs b/SiMay.RemoteControlsCore/ApplicationAdapterHandler/RemoteScreenAdapterHandler.cs index c6192a8..3cffe3f 100644 --- a/SiMay.RemoteControlsCore/ApplicationAdapterHandler/RemoteScreenAdapterHandler.cs +++ b/SiMay.RemoteControlsCore/ApplicationAdapterHandler/RemoteScreenAdapterHandler.cs @@ -12,7 +12,7 @@ using SiMay.Core.PacketModelBinding; using SiMay.Core.Packets; using SiMay.Core.Packets.Screen; using SiMay.Core.ScreenSpy.Entitys; -using SiMay.Net.SessionProvider.SessionBased; +using SiMay.Net.SessionProvider; using SiMay.RemoteControlsCore.Enum; using static SiMay.Serialize.Standard.PacketSerializeHelper; diff --git a/SiMay.RemoteControlsCore/ApplicationAdapterHandler/ShellAdapterHandler.cs b/SiMay.RemoteControlsCore/ApplicationAdapterHandler/ShellAdapterHandler.cs index 18c24e7..d98c1a7 100644 --- a/SiMay.RemoteControlsCore/ApplicationAdapterHandler/ShellAdapterHandler.cs +++ b/SiMay.RemoteControlsCore/ApplicationAdapterHandler/ShellAdapterHandler.cs @@ -7,7 +7,7 @@ using SiMay.Core; using SiMay.Core.Extensions; using SiMay.Core.PacketModelBinder.Attributes; using SiMay.Core.PacketModelBinding; -using SiMay.Net.SessionProvider.SessionBased; +using SiMay.Net.SessionProvider; namespace SiMay.RemoteControlsCore.HandlerAdapters { diff --git a/SiMay.RemoteControlsCore/ApplicationAdapterHandler/StartupAdapterHandler.cs b/SiMay.RemoteControlsCore/ApplicationAdapterHandler/StartupAdapterHandler.cs index 9f2016d..9b525f5 100644 --- a/SiMay.RemoteControlsCore/ApplicationAdapterHandler/StartupAdapterHandler.cs +++ b/SiMay.RemoteControlsCore/ApplicationAdapterHandler/StartupAdapterHandler.cs @@ -8,7 +8,7 @@ using SiMay.Core.Enums; using SiMay.Core.PacketModelBinder.Attributes; using SiMay.Core.PacketModelBinding; using SiMay.Core.Packets.Startup; -using SiMay.Net.SessionProvider.SessionBased; +using SiMay.Net.SessionProvider; namespace SiMay.RemoteControlsCore.HandlerAdapters { diff --git a/SiMay.RemoteControlsCore/ApplicationAdapterHandler/SystemAdapterHandler.cs b/SiMay.RemoteControlsCore/ApplicationAdapterHandler/SystemAdapterHandler.cs index ed9d39b..60c51fa 100644 --- a/SiMay.RemoteControlsCore/ApplicationAdapterHandler/SystemAdapterHandler.cs +++ b/SiMay.RemoteControlsCore/ApplicationAdapterHandler/SystemAdapterHandler.cs @@ -8,7 +8,7 @@ using SiMay.Core.PacketModelBinder.Attributes; using SiMay.Core.PacketModelBinding; using SiMay.Core.Packets; using SiMay.Core.Packets.SysManager; -using SiMay.Net.SessionProvider.SessionBased; +using SiMay.Net.SessionProvider; namespace SiMay.RemoteControlsCore.HandlerAdapters { diff --git a/SiMay.RemoteControlsCore/ApplicationAdapterHandler/TcpConnectionAdapterHandler.cs b/SiMay.RemoteControlsCore/ApplicationAdapterHandler/TcpConnectionAdapterHandler.cs index 7c93523..e1e7e47 100644 --- a/SiMay.RemoteControlsCore/ApplicationAdapterHandler/TcpConnectionAdapterHandler.cs +++ b/SiMay.RemoteControlsCore/ApplicationAdapterHandler/TcpConnectionAdapterHandler.cs @@ -7,7 +7,7 @@ using SiMay.Core; using SiMay.Core.PacketModelBinder.Attributes; using SiMay.Core.PacketModelBinding; using SiMay.Core.Packets.TcpConnection; -using SiMay.Net.SessionProvider.SessionBased; +using SiMay.Net.SessionProvider; namespace SiMay.RemoteControlsCore.HandlerAdapters { diff --git a/SiMay.RemoteControlsCore/ApplicationAdapterHandler/VideoAppAdapterHandler.cs b/SiMay.RemoteControlsCore/ApplicationAdapterHandler/VideoAppAdapterHandler.cs index 6753e26..39089da 100644 --- a/SiMay.RemoteControlsCore/ApplicationAdapterHandler/VideoAppAdapterHandler.cs +++ b/SiMay.RemoteControlsCore/ApplicationAdapterHandler/VideoAppAdapterHandler.cs @@ -9,7 +9,7 @@ using SiMay.Basic; using SiMay.Core; using SiMay.Core.PacketModelBinder.Attributes; using SiMay.Core.PacketModelBinding; -using SiMay.Net.SessionProvider.SessionBased; +using SiMay.Net.SessionProvider; namespace SiMay.RemoteControlsCore.HandlerAdapters { diff --git a/SiMay.RemoteControlsCore/Entitys/SessionSyncContext.cs b/SiMay.RemoteControlsCore/Entitys/SessionSyncContext.cs index d18062f..ef62dc4 100644 --- a/SiMay.RemoteControlsCore/Entitys/SessionSyncContext.cs +++ b/SiMay.RemoteControlsCore/Entitys/SessionSyncContext.cs @@ -1,4 +1,4 @@ -using SiMay.Net.SessionProvider.SessionBased; +using SiMay.Net.SessionProvider; using System; using System.Collections.Generic; using System.Linq; diff --git a/SiMay.RemoteControlsCore/MainApplicationAdapterHandler.cs b/SiMay.RemoteControlsCore/MainApplicationAdapterHandler.cs index 6ea30cc..719a12b 100644 --- a/SiMay.RemoteControlsCore/MainApplicationAdapterHandler.cs +++ b/SiMay.RemoteControlsCore/MainApplicationAdapterHandler.cs @@ -5,9 +5,8 @@ using SiMay.Core.Extensions; using SiMay.Core.PacketModelBinder.Attributes; using SiMay.Core.Packets; using SiMay.Net.SessionProvider; -using SiMay.Net.SessionProvider.Delegate; -using SiMay.Net.SessionProvider.Notify; -using SiMay.Net.SessionProvider.SessionBased; +using SiMay.Net.SessionProvider.Providers; +using SiMay.Sockets.Tcp; using System; using System.Collections.Generic; using System.Drawing; @@ -56,7 +55,7 @@ namespace SiMay.RemoteControlsCore /// /// 代理协议事件 /// - public event OnProxyNotify OnProxyNotifyHandlerEvent; + public event Action OnProxyNotifyHandlerEvent; /// /// 监听日志事件 @@ -93,48 +92,56 @@ namespace SiMay.RemoteControlsCore /// 是否已启动 /// private bool _launch; - public void StartService() + + public void StartApp() { if (_launch) return; _launch = true; - AppConfiguration.AccessId = DateTime.Now.ToFileTimeUtc();//暂时使用UTC时间作为主控端标识 - ThreadHelper.CreateThread(ApplicationResetThread, true); - var sessionMode = int.Parse(AppConfiguration.SessionMode).ConvertTo(); + this.StartService(); + } + + public void StartService() + { + var providerType = int.Parse(AppConfiguration.SessionMode).ConvertTo(); - string ip = sessionMode == SessionProviderType.TcpServiceSession + string ip = providerType == SessionProviderType.TcpServiceSession ? AppConfiguration.IPAddress : AppConfiguration.ServiceIPAddress; - int port = sessionMode == SessionProviderType.TcpServiceSession + int port = providerType == SessionProviderType.TcpServiceSession ? AppConfiguration.Port : AppConfiguration.ServicePort; - int maxconnectCount = AppConfiguration.MaxConnectCount; + AppConfiguration.UseAccessId = !AppConfiguration.EnabledAnonyMous ? AppConfiguration.AccessId : DateTime.Now.ToFileTimeUtc(); + + int maxConnectCount = AppConfiguration.MaxConnectCount; - var options = new SessionProviderOptions + var providerOptions = new SessionProviderOptions { ServiceIPEndPoint = new IPEndPoint(IPAddress.Parse(ip), port), - PendingConnectionBacklog = maxconnectCount, - AccessKey = long.Parse(AppConfiguration.AccessKey) + PendingConnectionBacklog = maxConnectCount, + AccessId = AppConfiguration.UseAccessId,//暂时使用UTC时间作为主控端标识 + MainAppAccessKey = AppConfiguration.MainAppAccessKey, + MaxPacketSize = 1024 * 1024 * 2, + AccessKey = long.Parse(AppConfiguration.AccessKey), + SessionProviderType = providerType }; - var providerType = sessionMode; - options.SessionProviderType = providerType; if (providerType == SessionProviderType.TcpServiceSession) { - if (StartServiceProvider(options)) + if (StartServiceProvider(providerOptions)) this.OnLogHandlerEvent?.Invoke($"SiMay远程监控管理系统端口 {port.ToString()} 监听成功!", LogSeverityLevel.Information); else this.OnLogHandlerEvent?.Invoke($"SiMay远程监控管理系统端口 {port.ToString()} 启动失败,请检查配置!", LogSeverityLevel.Warning); } else { - if (StartProxySessionProvider(options)) + if (StartProxySessionProvider(providerOptions)) this.OnLogHandlerEvent?.Invoke($"SiMay远程监控管理系统初始化成功!", LogSeverityLevel.Information); else this.OnLogHandlerEvent?.Invoke($"SiMay远程监控管理系统初始化发生错误,请注意检查配置!", LogSeverityLevel.Warning); @@ -142,7 +149,8 @@ namespace SiMay.RemoteControlsCore bool StartServiceProvider(SessionProviderOptions providerOptions) { - SessionProvider = SessionProviderFactory.CreateTcpSessionProvider(providerOptions, OnNotifyProc); + SessionProvider = SessionProviderFactory.CreateTcpSessionProvider(providerOptions); + SessionProvider.SessionNotifyEventHandler += OnNotifyProc; try { SessionProvider.StartSerivce(); @@ -157,7 +165,12 @@ namespace SiMay.RemoteControlsCore bool StartProxySessionProvider(SessionProviderOptions providerOptions) { - SessionProvider = SessionProviderFactory.CreateProxySessionProvider(options, OnNotifyProc, OnProxyNotifyHandlerEvent); + SessionProvider = SessionProviderFactory.CreateProxySessionProvider(providerOptions); + SessionProvider.SessionNotifyEventHandler += OnNotifyProc; + + if (SessionProvider is TcpProxySessionProvider proxySessionProvider) + proxySessionProvider.ProxyProviderNotify += OnProxyNotifyHandlerEvent; + try { SessionProvider.StartSerivce(); @@ -176,9 +189,9 @@ namespace SiMay.RemoteControlsCore ///

/// /// - private void OnNotifyProc(SessionCompletedNotify notify, SessionProviderContext session) + private void OnNotifyProc(SessionProviderContext session, TcpSessionNotify notify) { - if (SynchronizationContext == null) + if (SynchronizationContext.IsNull()) NotifyProc(null); else SynchronizationContext.Send(NotifyProc, null); @@ -189,7 +202,7 @@ namespace SiMay.RemoteControlsCore { switch (notify) { - case SessionCompletedNotify.OnConnected: + case TcpSessionNotify.OnConnected: //先分配好工作类型,等待工作指令分配新的工作类型 session.AppTokens = new object[SysConstants.INDEX_COUNT] { @@ -197,18 +210,18 @@ namespace SiMay.RemoteControlsCore null }; break; - case SessionCompletedNotify.OnSend: + case TcpSessionNotify.OnSend: //耗时操作会导致性能严重降低 this.OnTransmitHandlerEvent?.Invoke(session); break; - case SessionCompletedNotify.OnRecv: + case TcpSessionNotify.OnDataReceiveing: //耗时操作会导致性能严重降低 this.OnReceiveHandlerEvent?.Invoke(session); break; - case SessionCompletedNotify.OnReceived: + case TcpSessionNotify.OnDataReceived: this.OnReceiveComplete(session); break; - case SessionCompletedNotify.OnClosed: + case TcpSessionNotify.OnClosed: this.OnClosed(session); break; } diff --git a/SiMay.RemoteControlsCore/SiMay.RemoteControlsCore.csproj b/SiMay.RemoteControlsCore/SiMay.RemoteControlsCore.csproj index 94f0dd5..cb9abca 100644 --- a/SiMay.RemoteControlsCore/SiMay.RemoteControlsCore.csproj +++ b/SiMay.RemoteControlsCore/SiMay.RemoteControlsCore.csproj @@ -100,6 +100,10 @@ {9525A4AA-6731-4AB2-8CD0-ADDF7940FE32} SiMay.Serialize.Standard + + {866F8FE0-EE58-4D38-8BE7-CBDD19DD1B40} + SiMay.Sockets.Standard + diff --git a/SiMay.RemoteMonitor/Application/ScreenApplication.cs b/SiMay.RemoteMonitor/Application/ScreenApplication.cs index 77e409c..11ee7f9 100644 --- a/SiMay.RemoteMonitor/Application/ScreenApplication.cs +++ b/SiMay.RemoteMonitor/Application/ScreenApplication.cs @@ -10,7 +10,6 @@ using System.Windows.Forms; using SiMay.RemoteControlsCore; using SiMay.RemoteControlsCore.Enum; using SiMay.RemoteMonitor.MainApplication; -using SiMay.Net.SessionProvider.SessionBased; using SiMay.RemoteControlsCore.HandlerAdapters; using static SiMay.RemoteMonitor.Win32Api; using static SiMay.Serialize.Standard.PacketSerializeHelper; diff --git a/SiMay.RemoteMonitor/MainApplication/AppSettingForm.Designer.cs b/SiMay.RemoteMonitor/MainApplication/AppSettingForm.Designer.cs index e7ff0d7..502da12 100644 --- a/SiMay.RemoteMonitor/MainApplication/AppSettingForm.Designer.cs +++ b/SiMay.RemoteMonitor/MainApplication/AppSettingForm.Designer.cs @@ -42,6 +42,11 @@ this.label4 = new System.Windows.Forms.Label(); this.maximizeCheckBox = new System.Windows.Forms.CheckBox(); this.panel2 = new System.Windows.Forms.Panel(); + this.enableAnonymous = new System.Windows.Forms.CheckBox(); + this.txtAccessId = new System.Windows.Forms.TextBox(); + this.label16 = new System.Windows.Forms.Label(); + this.txtMainAppAccessKey = new System.Windows.Forms.TextBox(); + this.label15 = new System.Windows.Forms.Label(); this.label13 = new System.Windows.Forms.Label(); this.txtservice_port = new System.Windows.Forms.TextBox(); this.label12 = new System.Windows.Forms.Label(); @@ -66,86 +71,96 @@ // save // this.save.Anchor = ((System.Windows.Forms.AnchorStyles)((System.Windows.Forms.AnchorStyles.Bottom | System.Windows.Forms.AnchorStyles.Right))); - this.save.Location = new System.Drawing.Point(338, 10); + this.save.Location = new System.Drawing.Point(451, 12); + this.save.Margin = new System.Windows.Forms.Padding(4); this.save.Name = "save"; - this.save.Size = new System.Drawing.Size(75, 26); + this.save.Size = new System.Drawing.Size(100, 32); this.save.TabIndex = 0; this.save.Text = "保存设置"; this.save.UseVisualStyleBackColor = true; this.save.Click += new System.EventHandler(this.save_Click); // - // connectNum + // connectLimitCount // - this.connectLimitCount.Location = new System.Drawing.Point(185, 135); - this.connectLimitCount.Name = "connectNum"; - this.connectLimitCount.Size = new System.Drawing.Size(115, 21); + this.connectLimitCount.Location = new System.Drawing.Point(247, 169); + this.connectLimitCount.Margin = new System.Windows.Forms.Padding(4); + this.connectLimitCount.Name = "connectLimitCount"; + this.connectLimitCount.Size = new System.Drawing.Size(152, 25); this.connectLimitCount.TabIndex = 13; // // label3 // this.label3.AutoSize = true; - this.label3.Location = new System.Drawing.Point(107, 137); + this.label3.Location = new System.Drawing.Point(143, 171); + this.label3.Margin = new System.Windows.Forms.Padding(4, 0, 4, 0); this.label3.Name = "label3"; - this.label3.Size = new System.Drawing.Size(71, 12); + this.label3.Size = new System.Drawing.Size(90, 15); this.label3.TabIndex = 12; this.label3.Text = "最大连接数:"; // // port // - this.port.Location = new System.Drawing.Point(185, 81); + this.port.Location = new System.Drawing.Point(247, 101); + this.port.Margin = new System.Windows.Forms.Padding(4); this.port.Name = "port"; - this.port.Size = new System.Drawing.Size(115, 21); + this.port.Size = new System.Drawing.Size(152, 25); this.port.TabIndex = 11; // // label2 // this.label2.AutoSize = true; - this.label2.Location = new System.Drawing.Point(119, 84); + this.label2.Location = new System.Drawing.Point(159, 105); + this.label2.Margin = new System.Windows.Forms.Padding(4, 0, 4, 0); this.label2.Name = "label2"; - this.label2.Size = new System.Drawing.Size(59, 12); + this.label2.Size = new System.Drawing.Size(75, 15); this.label2.TabIndex = 10; this.label2.Text = "监听端口:"; // // ip // - this.ip.Location = new System.Drawing.Point(185, 54); + this.ip.Location = new System.Drawing.Point(247, 68); + this.ip.Margin = new System.Windows.Forms.Padding(4); this.ip.Name = "ip"; - this.ip.Size = new System.Drawing.Size(115, 21); + this.ip.Size = new System.Drawing.Size(152, 25); this.ip.TabIndex = 9; // // label1 // this.label1.AutoSize = true; - this.label1.Location = new System.Drawing.Point(108, 57); + this.label1.Location = new System.Drawing.Point(144, 71); + this.label1.Margin = new System.Windows.Forms.Padding(4, 0, 4, 0); this.label1.Name = "label1"; - this.label1.Size = new System.Drawing.Size(71, 12); + this.label1.Size = new System.Drawing.Size(90, 15); this.label1.TabIndex = 8; this.label1.Text = "服务器地址:"; // // conPwd // - this.conPwd.Location = new System.Drawing.Point(185, 108); + this.conPwd.Location = new System.Drawing.Point(247, 135); + this.conPwd.Margin = new System.Windows.Forms.Padding(4); this.conPwd.MaxLength = 6; this.conPwd.Name = "conPwd"; - this.conPwd.Size = new System.Drawing.Size(115, 21); + this.conPwd.Size = new System.Drawing.Size(152, 25); this.conPwd.TabIndex = 17; this.conPwd.KeyPress += new System.Windows.Forms.KeyPressEventHandler(this.conPwd_KeyPress); // // label5 // this.label5.AutoSize = true; - this.label5.Location = new System.Drawing.Point(119, 111); + this.label5.Location = new System.Drawing.Point(159, 139); + this.label5.Margin = new System.Windows.Forms.Padding(4, 0, 4, 0); this.label5.Name = "label5"; - this.label5.Size = new System.Drawing.Size(59, 12); + this.label5.Size = new System.Drawing.Size(75, 15); this.label5.TabIndex = 16; this.label5.Text = "连接密码:"; // // button1 // this.button1.Anchor = ((System.Windows.Forms.AnchorStyles)((System.Windows.Forms.AnchorStyles.Bottom | System.Windows.Forms.AnchorStyles.Right))); - this.button1.Location = new System.Drawing.Point(419, 10); + this.button1.Location = new System.Drawing.Point(559, 12); + this.button1.Margin = new System.Windows.Forms.Padding(4); this.button1.Name = "button1"; - this.button1.Size = new System.Drawing.Size(75, 26); + this.button1.Size = new System.Drawing.Size(100, 32); this.button1.TabIndex = 18; this.button1.Text = "关闭"; this.button1.UseVisualStyleBackColor = true; @@ -156,32 +171,40 @@ this.funComboBox.DropDownStyle = System.Windows.Forms.ComboBoxStyle.DropDownList; this.funComboBox.FlatStyle = System.Windows.Forms.FlatStyle.System; this.funComboBox.FormattingEnabled = true; - this.funComboBox.Location = new System.Drawing.Point(185, 161); + this.funComboBox.Location = new System.Drawing.Point(247, 201); + this.funComboBox.Margin = new System.Windows.Forms.Padding(4); this.funComboBox.Name = "funComboBox"; - this.funComboBox.Size = new System.Drawing.Size(115, 20); + this.funComboBox.Size = new System.Drawing.Size(152, 23); this.funComboBox.TabIndex = 26; // // label4 // this.label4.AutoSize = true; - this.label4.Location = new System.Drawing.Point(95, 165); + this.label4.Location = new System.Drawing.Point(127, 206); + this.label4.Margin = new System.Windows.Forms.Padding(4, 0, 4, 0); this.label4.Name = "label4"; - this.label4.Size = new System.Drawing.Size(83, 12); + this.label4.Size = new System.Drawing.Size(105, 15); this.label4.TabIndex = 25; this.label4.Text = "双击屏幕打开:"; // // maximizeCheckBox // this.maximizeCheckBox.AutoSize = true; - this.maximizeCheckBox.Location = new System.Drawing.Point(185, 190); + this.maximizeCheckBox.Location = new System.Drawing.Point(247, 238); + this.maximizeCheckBox.Margin = new System.Windows.Forms.Padding(4); this.maximizeCheckBox.Name = "maximizeCheckBox"; - this.maximizeCheckBox.Size = new System.Drawing.Size(96, 16); + this.maximizeCheckBox.Size = new System.Drawing.Size(119, 19); this.maximizeCheckBox.TabIndex = 24; this.maximizeCheckBox.Text = "启动时最大化"; this.maximizeCheckBox.UseVisualStyleBackColor = true; // // panel2 // + this.panel2.Controls.Add(this.enableAnonymous); + this.panel2.Controls.Add(this.txtAccessId); + this.panel2.Controls.Add(this.label16); + this.panel2.Controls.Add(this.txtMainAppAccessKey); + this.panel2.Controls.Add(this.label15); this.panel2.Controls.Add(this.label13); this.panel2.Controls.Add(this.txtservice_port); this.panel2.Controls.Add(this.label12); @@ -205,67 +228,120 @@ this.panel2.Controls.Add(this.connectLimitCount); this.panel2.Controls.Add(this.label2); this.panel2.Controls.Add(this.label5); - this.panel2.Location = new System.Drawing.Point(32, 2); - this.panel2.Margin = new System.Windows.Forms.Padding(2); + this.panel2.Location = new System.Drawing.Point(43, 2); + this.panel2.Margin = new System.Windows.Forms.Padding(3, 2, 3, 2); this.panel2.Name = "panel2"; - this.panel2.Size = new System.Drawing.Size(405, 438); + this.panel2.Size = new System.Drawing.Size(550, 655); this.panel2.TabIndex = 0; // + // enableAnonymous + // + this.enableAnonymous.AutoSize = true; + this.enableAnonymous.Location = new System.Drawing.Point(163, 428); + this.enableAnonymous.Name = "enableAnonymous"; + this.enableAnonymous.Size = new System.Drawing.Size(354, 19); + this.enableAnonymous.TabIndex = 45; + this.enableAnonymous.Text = "匿名登陆(随机Id,需中间服务开启允许匿名登陆)"; + this.enableAnonymous.UseVisualStyleBackColor = true; + this.enableAnonymous.CheckedChanged += new System.EventHandler(this.enableAnonymous_CheckedChanged); + // + // txtAccessId + // + this.txtAccessId.Location = new System.Drawing.Point(247, 396); + this.txtAccessId.Margin = new System.Windows.Forms.Padding(4); + this.txtAccessId.Name = "txtAccessId"; + this.txtAccessId.Size = new System.Drawing.Size(152, 25); + this.txtAccessId.TabIndex = 44; + // + // label16 + // + this.label16.AutoSize = true; + this.label16.Location = new System.Drawing.Point(160, 399); + this.label16.Margin = new System.Windows.Forms.Padding(4, 0, 4, 0); + this.label16.Name = "label16"; + this.label16.Size = new System.Drawing.Size(79, 15); + this.label16.TabIndex = 43; + this.label16.Text = "AccessId:"; + // + // txtMainAppAccessKey + // + this.txtMainAppAccessKey.Location = new System.Drawing.Point(247, 503); + this.txtMainAppAccessKey.Margin = new System.Windows.Forms.Padding(4); + this.txtMainAppAccessKey.Name = "txtMainAppAccessKey"; + this.txtMainAppAccessKey.Size = new System.Drawing.Size(152, 25); + this.txtMainAppAccessKey.TabIndex = 42; + // + // label15 + // + this.label15.AutoSize = true; + this.label15.Location = new System.Drawing.Point(96, 506); + this.label15.Margin = new System.Windows.Forms.Padding(4, 0, 4, 0); + this.label15.Name = "label15"; + this.label15.Size = new System.Drawing.Size(143, 15); + this.label15.TabIndex = 41; + this.label15.Text = "MainAppAccessKey:"; + // // label13 // this.label13.AutoSize = true; - this.label13.Location = new System.Drawing.Point(95, 190); + this.label13.Location = new System.Drawing.Point(127, 238); + this.label13.Margin = new System.Windows.Forms.Padding(4, 0, 4, 0); this.label13.Name = "label13"; - this.label13.Size = new System.Drawing.Size(83, 12); + this.label13.Size = new System.Drawing.Size(105, 15); this.label13.TabIndex = 40; this.label13.Text = "窗口启动状态:"; // // txtservice_port // - this.txtservice_port.Location = new System.Drawing.Point(185, 282); + this.txtservice_port.Location = new System.Drawing.Point(247, 352); + this.txtservice_port.Margin = new System.Windows.Forms.Padding(4); this.txtservice_port.Name = "txtservice_port"; - this.txtservice_port.Size = new System.Drawing.Size(115, 21); + this.txtservice_port.Size = new System.Drawing.Size(152, 25); this.txtservice_port.TabIndex = 39; // // label12 // this.label12.AutoSize = true; - this.label12.Location = new System.Drawing.Point(120, 286); + this.label12.Location = new System.Drawing.Point(164, 355); + this.label12.Margin = new System.Windows.Forms.Padding(4, 0, 4, 0); this.label12.Name = "label12"; - this.label12.Size = new System.Drawing.Size(59, 12); + this.label12.Size = new System.Drawing.Size(75, 15); this.label12.TabIndex = 38; this.label12.Text = "服务端口:"; // // txtservice_address // - this.txtservice_address.Location = new System.Drawing.Point(185, 255); + this.txtservice_address.Location = new System.Drawing.Point(247, 319); + this.txtservice_address.Margin = new System.Windows.Forms.Padding(4); this.txtservice_address.Name = "txtservice_address"; - this.txtservice_address.Size = new System.Drawing.Size(115, 21); + this.txtservice_address.Size = new System.Drawing.Size(152, 25); this.txtservice_address.TabIndex = 37; // // label10 // this.label10.AutoSize = true; - this.label10.Location = new System.Drawing.Point(107, 258); + this.label10.Location = new System.Drawing.Point(149, 322); + this.label10.Margin = new System.Windows.Forms.Padding(4, 0, 4, 0); this.label10.Name = "label10"; - this.label10.Size = new System.Drawing.Size(71, 12); + this.label10.Size = new System.Drawing.Size(90, 15); this.label10.TabIndex = 36; this.label10.Text = "服务器地址:"; // // accessKey // - this.accessKey.Location = new System.Drawing.Point(185, 309); + this.accessKey.Location = new System.Drawing.Point(247, 470); + this.accessKey.Margin = new System.Windows.Forms.Padding(4); this.accessKey.Name = "accessKey"; - this.accessKey.Size = new System.Drawing.Size(115, 21); + this.accessKey.Size = new System.Drawing.Size(152, 25); this.accessKey.TabIndex = 35; - this.accessKey.UseSystemPasswordChar = true; // // label11 // this.label11.AutoSize = true; - this.label11.Location = new System.Drawing.Point(113, 312); + this.label11.Location = new System.Drawing.Point(151, 474); + this.label11.Margin = new System.Windows.Forms.Padding(4, 0, 4, 0); this.label11.Name = "label11"; - this.label11.Size = new System.Drawing.Size(65, 12); + this.label11.Size = new System.Drawing.Size(87, 15); this.label11.TabIndex = 34; this.label11.Text = "AccessKey:"; // @@ -273,27 +349,28 @@ // this.label9.AutoSize = true; this.label9.Font = new System.Drawing.Font("宋体", 9F, System.Drawing.FontStyle.Bold, System.Drawing.GraphicsUnit.Point, ((byte)(134))); - this.label9.Location = new System.Drawing.Point(95, 227); - this.label9.Margin = new System.Windows.Forms.Padding(2, 0, 2, 0); + this.label9.Location = new System.Drawing.Point(127, 284); this.label9.Name = "label9"; - this.label9.Size = new System.Drawing.Size(70, 12); + this.label9.Size = new System.Drawing.Size(87, 15); this.label9.TabIndex = 31; this.label9.Text = "会话服务器"; // // pwdTextBox // - this.pwdTextBox.Location = new System.Drawing.Point(185, 383); + this.pwdTextBox.Location = new System.Drawing.Point(247, 594); + this.pwdTextBox.Margin = new System.Windows.Forms.Padding(4); this.pwdTextBox.Name = "pwdTextBox"; - this.pwdTextBox.Size = new System.Drawing.Size(115, 21); + this.pwdTextBox.Size = new System.Drawing.Size(152, 25); this.pwdTextBox.TabIndex = 30; this.pwdTextBox.UseSystemPasswordChar = true; // // label8 // this.label8.AutoSize = true; - this.label8.Location = new System.Drawing.Point(95, 386); + this.label8.Location = new System.Drawing.Point(127, 597); + this.label8.Margin = new System.Windows.Forms.Padding(4, 0, 4, 0); this.label8.Name = "label8"; - this.label8.Size = new System.Drawing.Size(83, 12); + this.label8.Size = new System.Drawing.Size(105, 15); this.label8.TabIndex = 29; this.label8.Text = "修改解锁密码:"; // @@ -301,10 +378,9 @@ // this.label7.AutoSize = true; this.label7.Font = new System.Drawing.Font("宋体", 9F, System.Drawing.FontStyle.Bold, System.Drawing.GraphicsUnit.Point, ((byte)(134))); - this.label7.Location = new System.Drawing.Point(95, 352); - this.label7.Margin = new System.Windows.Forms.Padding(2, 0, 2, 0); + this.label7.Location = new System.Drawing.Point(143, 555); this.label7.Name = "label7"; - this.label7.Size = new System.Drawing.Size(57, 12); + this.label7.Size = new System.Drawing.Size(71, 15); this.label7.TabIndex = 28; this.label7.Text = "锁定密码"; // @@ -312,10 +388,9 @@ // this.label6.AutoSize = true; this.label6.Font = new System.Drawing.Font("宋体", 9F, System.Drawing.FontStyle.Bold, System.Drawing.GraphicsUnit.Point, ((byte)(134))); - this.label6.Location = new System.Drawing.Point(95, 18); - this.label6.Margin = new System.Windows.Forms.Padding(2, 0, 2, 0); + this.label6.Location = new System.Drawing.Point(127, 22); this.label6.Name = "label6"; - this.label6.Size = new System.Drawing.Size(57, 12); + this.label6.Size = new System.Drawing.Size(71, 15); this.label6.TabIndex = 27; this.label6.Text = "基本设置"; // @@ -326,10 +401,10 @@ this.panel4.Controls.Add(this.button1); this.panel4.Controls.Add(this.save); this.panel4.Dock = System.Windows.Forms.DockStyle.Bottom; - this.panel4.Location = new System.Drawing.Point(0, 300); - this.panel4.Margin = new System.Windows.Forms.Padding(2); + this.panel4.Location = new System.Drawing.Point(0, 375); + this.panel4.Margin = new System.Windows.Forms.Padding(3, 2, 3, 2); this.panel4.Name = "panel4"; - this.panel4.Size = new System.Drawing.Size(503, 45); + this.panel4.Size = new System.Drawing.Size(671, 56); this.panel4.TabIndex = 28; // // sessionModeList @@ -340,17 +415,19 @@ this.sessionModeList.Items.AddRange(new object[] { "本地服务器", "中间会话服务"}); - this.sessionModeList.Location = new System.Drawing.Point(63, 11); + this.sessionModeList.Location = new System.Drawing.Point(84, 14); + this.sessionModeList.Margin = new System.Windows.Forms.Padding(4); this.sessionModeList.Name = "sessionModeList"; - this.sessionModeList.Size = new System.Drawing.Size(121, 20); + this.sessionModeList.Size = new System.Drawing.Size(160, 23); this.sessionModeList.TabIndex = 20; // // label14 // this.label14.AutoSize = true; - this.label14.Location = new System.Drawing.Point(4, 15); + this.label14.Location = new System.Drawing.Point(5, 19); + this.label14.Margin = new System.Windows.Forms.Padding(4, 0, 4, 0); this.label14.Name = "label14"; - this.label14.Size = new System.Drawing.Size(59, 12); + this.label14.Size = new System.Drawing.Size(75, 15); this.label14.TabIndex = 19; this.label14.Text = "会话模式:"; // @@ -360,21 +437,22 @@ this.panel1.Controls.Add(this.panel2); this.panel1.Dock = System.Windows.Forms.DockStyle.Fill; this.panel1.Location = new System.Drawing.Point(0, 0); - this.panel1.Margin = new System.Windows.Forms.Padding(2); + this.panel1.Margin = new System.Windows.Forms.Padding(3, 2, 3, 2); this.panel1.Name = "panel1"; - this.panel1.Size = new System.Drawing.Size(503, 300); + this.panel1.Size = new System.Drawing.Size(671, 375); this.panel1.TabIndex = 29; // - // AppSettingDialog + // AppSettingForm // - this.AutoScaleDimensions = new System.Drawing.SizeF(6F, 12F); + this.AutoScaleDimensions = new System.Drawing.SizeF(8F, 15F); this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font; - this.ClientSize = new System.Drawing.Size(503, 345); + this.ClientSize = new System.Drawing.Size(671, 431); this.Controls.Add(this.panel1); this.Controls.Add(this.panel4); this.FormBorderStyle = System.Windows.Forms.FormBorderStyle.FixedSingle; + this.Margin = new System.Windows.Forms.Padding(4); this.MaximizeBox = false; - this.Name = "AppSettingDialog"; + this.Name = "AppSettingForm"; this.StartPosition = System.Windows.Forms.FormStartPosition.CenterScreen; this.Text = "系统设置"; this.Load += new System.EventHandler(this.SetForm_Load); @@ -419,5 +497,10 @@ private System.Windows.Forms.TextBox txtservice_address; private System.Windows.Forms.Label label10; private System.Windows.Forms.Label label13; + private System.Windows.Forms.CheckBox enableAnonymous; + private System.Windows.Forms.TextBox txtAccessId; + private System.Windows.Forms.Label label16; + private System.Windows.Forms.TextBox txtMainAppAccessKey; + private System.Windows.Forms.Label label15; } } \ No newline at end of file diff --git a/SiMay.RemoteMonitor/MainApplication/AppSettingForm.cs b/SiMay.RemoteMonitor/MainApplication/AppSettingForm.cs index 78a58f4..73f285e 100644 --- a/SiMay.RemoteMonitor/MainApplication/AppSettingForm.cs +++ b/SiMay.RemoteMonitor/MainApplication/AppSettingForm.cs @@ -36,6 +36,9 @@ namespace SiMay.RemoteMonitor.MainApplication AppConfiguration.SessionMode = sessionModeList.SelectedIndex.ToString(); AppConfiguration.ServiceIPAddress = txtservice_address.Text; AppConfiguration.ServicePort = int.Parse(txtservice_port.Text); + AppConfiguration.AccessId = long.Parse(txtAccessId.Text); + AppConfiguration.EnabledAnonyMous = enableAnonymous.Checked; + AppConfiguration.MainAppAccessKey = long.Parse(txtMainAppAccessKey.Text); DialogResult result = MessageBox.Show("设置完成,是否重启生效设置?", "提示", MessageBoxButtons.OKCancel, MessageBoxIcon.Exclamation); @@ -70,14 +73,18 @@ namespace SiMay.RemoteMonitor.MainApplication accessKey.Text = AppConfiguration.AccessKey; txtservice_address.Text = AppConfiguration.ServiceIPAddress; txtservice_port.Text = AppConfiguration.ServicePort.ToString(); + txtAccessId.Text = AppConfiguration.AccessId.ToString(); + txtMainAppAccessKey.Text = AppConfiguration.MainAppAccessKey.ToString(); int index = int.Parse(AppConfiguration.SessionMode); sessionModeList.SelectedIndex = index; - if (AppConfiguration.WindowMaximize) - maximizeCheckBox.Checked = true; - else - maximizeCheckBox.Checked = false; + maximizeCheckBox.Checked = AppConfiguration.WindowMaximize; + + enableAnonymous.Checked = AppConfiguration.EnabledAnonyMous; + txtAccessId.Enabled = AppConfiguration.EnabledAnonyMous; + + txtAccessId.Enabled = enableAnonymous.Checked ? false : true; } private void conPwd_KeyPress(object sender, KeyPressEventArgs e) @@ -94,5 +101,10 @@ namespace SiMay.RemoteMonitor.MainApplication { this.Close(); } + + private void enableAnonymous_CheckedChanged(object sender, EventArgs e) + { + txtAccessId.Enabled = enableAnonymous.Checked ? false : true; + } } } \ No newline at end of file diff --git a/SiMay.RemoteMonitor/MainApplication/BuilderServiceForm.cs b/SiMay.RemoteMonitor/MainApplication/BuilderServiceForm.cs index a2c9e20..9d084c3 100644 --- a/SiMay.RemoteMonitor/MainApplication/BuilderServiceForm.cs +++ b/SiMay.RemoteMonitor/MainApplication/BuilderServiceForm.cs @@ -36,7 +36,7 @@ namespace SiMay.RemoteMonitor.MainApplication Socket testSock = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp); try { - testSock.Connect(IPHelper.GetHostByName(mls_address.Text), int.Parse(mls_port.Text)); + testSock.Connect(HostHelper.GetHostByName(mls_address.Text), int.Parse(mls_port.Text)); testSock.Close(); MessageBoxHelper.ShowBoxExclamation("连接: " + mls_address.Text + ":" + mls_port.Text + " 成功!", "连接成功"); } diff --git a/SiMay.RemoteMonitor/MainApplication/MainApplication.cs b/SiMay.RemoteMonitor/MainApplication/MainApplication.cs index 7b17a20..cdae05a 100644 --- a/SiMay.RemoteMonitor/MainApplication/MainApplication.cs +++ b/SiMay.RemoteMonitor/MainApplication/MainApplication.cs @@ -1,8 +1,7 @@ using SiMay.Basic; using SiMay.Core; using SiMay.Core.Enums; -using SiMay.Net.SessionProvider.Notify; -using SiMay.Net.SessionProvider.SessionBased; +using SiMay.Net.SessionProvider; using SiMay.RemoteControlsCore; using SiMay.RemoteMonitor.Extensions; using SiMay.RemoteMonitor.Properties; @@ -253,7 +252,7 @@ namespace SiMay.RemoteMonitor.MainApplication this._appMainAdapterHandler.OnLoginHandlerEvent += OnLoginHandlerEvent; this._appMainAdapterHandler.OnLoginUpdateHandlerEvent += OnLoginUpdateHandlerEvent; this._appMainAdapterHandler.OnLogHandlerEvent += OnLogHandlerEvent; - this._appMainAdapterHandler.StartService(); + this._appMainAdapterHandler.StartApp(); } private void OnLoginUpdateHandlerEvent(SessionSyncContext syncContext) @@ -340,17 +339,17 @@ namespace SiMay.RemoteMonitor.MainApplication /// 代理协议事件 ///
/// - private void OnProxyNotify(ProxyNotify notify) + private void OnProxyNotify(ProxyProviderNotify notify, EventArgs arg) { switch (notify) { - case ProxyNotify.AccessKeyWrong: - MessageBoxHelper.ShowBoxExclamation("AccessKey错误,与会话服务器的连接自动关闭!"); + case ProxyProviderNotify.AccessIdOrKeyWrong: + this.InvokeUI(() => this.WriteRuninglog("AccessKey错误,与会话服务器的连接自动关闭!", "error")); break; - case ProxyNotify.LogOut: - if (MessageBox.Show("已有其他控制端连接服务器,本次连接已自动关闭,是否重新连接?", "提示", MessageBoxButtons.OKCancel, MessageBoxIcon.Exclamation, MessageBoxDefaultButton.Button1, MessageBoxOptions.DefaultDesktopOnly) == DialogResult.OK) + case ProxyProviderNotify.LogOut: + if (MessageBox.Show($"{arg.ConvertTo().Message},本次连接已自动关闭,是否重新连接?", "提示", MessageBoxButtons.OKCancel, MessageBoxIcon.Exclamation, MessageBoxDefaultButton.Button1, MessageBoxOptions.DefaultDesktopOnly) == DialogResult.OK) { - this._appMainAdapterHandler.SessionProvider.StartSerivce(); + this._appMainAdapterHandler.StartService(); } break; } diff --git a/SiMay.RemoteMonitor/UserControls/USessionListItem.cs b/SiMay.RemoteMonitor/UserControls/USessionListItem.cs index 8766dbe..81de8db 100644 --- a/SiMay.RemoteMonitor/UserControls/USessionListItem.cs +++ b/SiMay.RemoteMonitor/UserControls/USessionListItem.cs @@ -41,7 +41,7 @@ namespace SiMay.RemoteMonitor.UserControls this.SubItems.Add("Unknown"); } this.SubItems.Add(SessionSyncContext.KeyDictions[SysConstants.Remark].ConvertTo()); - this.SubItems.Add(SessionSyncContext.KeyDictions[SysConstants.OSVersion].ConvertTo()); + this.SubItems.Add(SessionSyncContext.KeyDictions[SysConstants.ServiceVison].ConvertTo()); this.SubItems.Add(SessionSyncContext.KeyDictions[SysConstants.StartRunTime].ConvertTo()); this.SubItems.Add(SessionSyncContext.KeyDictions[SysConstants.GroupName].ConvertTo()); } diff --git a/SiMay.RemoteMonitor/Win32Api.cs b/SiMay.RemoteMonitor/Win32Api.cs index 0c8cf5f..46e32c5 100644 --- a/SiMay.RemoteMonitor/Win32Api.cs +++ b/SiMay.RemoteMonitor/Win32Api.cs @@ -18,9 +18,8 @@ namespace SiMay.RemoteMonitor [DllImport("user32.dll")] public static extern IntPtr GetSystemMenu(IntPtr hWnd, bool bRevert);//获取窗体系统菜单 - [DllImport("user32.dll")] - + [DllImport("user32.dll")] public static extern bool InsertMenu(IntPtr hMenu, Int32 wPosition, Int32 wFlags, Int32 wIDNewItem, string lpNewItem);//插入菜单 [DllImport("user32.dll", CallingConvention = CallingConvention.StdCall)] diff --git a/SiMay.RemoteService.Loader/Interface/IAppMainService.cs b/SiMay.RemoteService.Loader/Interface/IAppMainService.cs index c8e80eb..e7c1cdb 100644 --- a/SiMay.RemoteService.Loader/Interface/IAppMainService.cs +++ b/SiMay.RemoteService.Loader/Interface/IAppMainService.cs @@ -9,6 +9,6 @@ namespace SiMay.RemoteService.Loader.Interface { public interface IAppMainService { - void Notify(TcpSocketCompletionNotify notify, TcpSocketSaeaSession session); + void Notify(TcpSessionNotify notify, TcpSocketSaeaSession session); } } diff --git a/SiMay.RemoteService.Loader/Program.cs b/SiMay.RemoteService.Loader/Program.cs index bcc1796..0f3556c 100644 --- a/SiMay.RemoteService.Loader/Program.cs +++ b/SiMay.RemoteService.Loader/Program.cs @@ -180,7 +180,7 @@ namespace SiMay.RemoteService.Loader _clientAgent.ConnectToServer(_iPEndPoint); } - private static void Notify(TcpSocketCompletionNotify notify, TcpSocketSaeaSession session) + private static void Notify(TcpSessionNotify notify, TcpSocketSaeaSession session) { if (_appMainService != null) { @@ -191,15 +191,15 @@ namespace SiMay.RemoteService.Loader switch (notify) { - case TcpSocketCompletionNotify.OnConnected: + case TcpSessionNotify.OnConnected: byte[] ack = BuilderAckPacket(_startParameter.AccessKey, CONNECT_MAIN); MsgHelper.SendMessage(session, C_GLOBAL_CONNECT, ack); break; - case TcpSocketCompletionNotify.OnSend: + case TcpSessionNotify.OnSend: break; - case TcpSocketCompletionNotify.OnDataReceiveing: + case TcpSessionNotify.OnDataReceiveing: break; - case TcpSocketCompletionNotify.OnDataReceived: + case TcpSessionNotify.OnDataReceived: switch (MsgHelper.GetMessageHead(session.CompletedBuffer)) { case S_GLOBAL_OK: @@ -215,7 +215,7 @@ namespace SiMay.RemoteService.Loader break; } break; - case TcpSocketCompletionNotify.OnClosed: + case TcpSessionNotify.OnClosed: if (_hasloadPlugin) return; diff --git a/SiMay.Serialize.Standard/ReflectCachePool/DynamicMethodMemberAccessor.cs b/SiMay.Serialize.Standard/ReflectCachePool/DynamicMethodMemberAccessor.cs index 9124568..08083cf 100644 --- a/SiMay.Serialize.Standard/ReflectCachePool/DynamicMethodMemberAccessor.cs +++ b/SiMay.Serialize.Standard/ReflectCachePool/DynamicMethodMemberAccessor.cs @@ -19,8 +19,7 @@ namespace SiMay.ReflectCache public static IMemberAccessor FindClassAccessor(Type instanceType) { IMemberAccessor classAccessor; - classAccessors.TryGetValue(instanceType, out classAccessor); - if (classAccessor == null) + if (!classAccessors.TryGetValue(instanceType, out classAccessor)) classAccessors.Add(instanceType, CreateMemberAccessor(instanceType)); return classAccessor; diff --git a/SiMay.Sockets.Standard/Tcp/Client/TcpSocketSaeaClientAgent.cs b/SiMay.Sockets.Standard/Tcp/Client/TcpSocketSaeaClientAgent.cs index 9e37657..d33393f 100644 --- a/SiMay.Sockets.Standard/Tcp/Client/TcpSocketSaeaClientAgent.cs +++ b/SiMay.Sockets.Standard/Tcp/Client/TcpSocketSaeaClientAgent.cs @@ -20,7 +20,7 @@ namespace SiMay.Sockets.Tcp.Client internal TcpSocketSaeaClientAgent( TcpSocketSaeaSessionType saeaSessionType, TcpSocketSaeaClientConfiguration configuration, - NotifyEventHandler completetionNotify) + NotifyEventHandler completetionNotify) : base(saeaSessionType, configuration, completetionNotify) { @@ -88,14 +88,14 @@ namespace SiMay.Sockets.Tcp.Client if (e != SocketError.Success) { LogHelper.WriteLog("client_connect-error"); - CompletetionNotify?.Invoke(TcpSocketCompletionNotify.OnClosed, session); + CompletetionNotify?.Invoke(TcpSessionNotify.OnClosed, session); SessionPool.Return(session); return; } TcpSocketSaeaSessions.Add(session); session.Attach(socket); - CompletetionNotify?.Invoke(TcpSocketCompletionNotify.OnConnected, session); + CompletetionNotify?.Invoke(TcpSessionNotify.OnConnected, session); session.StartProcess(); }); } diff --git a/SiMay.Sockets.Standard/Tcp/Server/TcpSocketSaeaServer.cs b/SiMay.Sockets.Standard/Tcp/Server/TcpSocketSaeaServer.cs index b50b905..1ce5941 100644 --- a/SiMay.Sockets.Standard/Tcp/Server/TcpSocketSaeaServer.cs +++ b/SiMay.Sockets.Standard/Tcp/Server/TcpSocketSaeaServer.cs @@ -22,7 +22,7 @@ namespace SiMay.Sockets.Tcp.Server internal TcpSocketSaeaServer( TcpSocketSaeaSessionType saeaSessionType, TcpSocketSaeaServerConfiguration configuration, - NotifyEventHandler completetionNotify) + NotifyEventHandler completetionNotify) : base(saeaSessionType, configuration, completetionNotify) { this._config = configuration; @@ -93,7 +93,7 @@ namespace SiMay.Sockets.Tcp.Server var session = SessionPool.Take(); session.Attach(acceptedSocket); this.TcpSocketSaeaSessions.Add(session); - this.CompletetionNotify?.Invoke(TcpSocketCompletionNotify.OnConnected, session); + this.CompletetionNotify?.Invoke(TcpSessionNotify.OnConnected, session); session.StartProcess(); } diff --git a/SiMay.Sockets.Standard/Tcp/Session/TcpSocketSaeaFullBased.cs b/SiMay.Sockets.Standard/Tcp/Session/TcpSocketSaeaFullBased.cs index 9aedfbe..87ab401 100644 --- a/SiMay.Sockets.Standard/Tcp/Session/TcpSocketSaeaFullBased.cs +++ b/SiMay.Sockets.Standard/Tcp/Session/TcpSocketSaeaFullBased.cs @@ -21,7 +21,7 @@ namespace SiMay.Sockets.Tcp.Session TcpSocketConfigurationBase configuration, SaeaAwaiterPool handlerSaeaPool, SessionPool sessionPool, - NotifyEventHandler notifyEventHandler, + NotifyEventHandler notifyEventHandler, TcpSocketSaeaEngineBased agent) : base(notifyEventHandler, configuration, handlerSaeaPool, sessionPool, agent) => CompletedBuffer = new byte[configuration.ReceiveBufferSize]; @@ -96,7 +96,7 @@ namespace SiMay.Sockets.Tcp.Session } this.ReceiveBytesTransferred = bytesTransferred; - NotifyEventHandler?.Invoke(TcpSocketCompletionNotify.OnDataReceiveing, this); + NotifyEventHandler?.Invoke(TcpSessionNotify.OnDataReceiveing, this); awaiter.Saea.SetBuffer(CompletedBuffer, 0, CompletedBuffer.Length); SaeaExHelper.ReceiveAsync(this.Socket, awaiter, PacketPartProcess); @@ -124,7 +124,7 @@ namespace SiMay.Sockets.Tcp.Session this.SendTransferredBytes = a.Saea.Buffer.Length; HandlerSaeaPool.Return(awaiter); - this.NotifyEventHandler?.Invoke(TcpSocketCompletionNotify.OnSend, this); + this.NotifyEventHandler?.Invoke(TcpSessionNotify.OnSend, this); }); } @@ -151,7 +151,7 @@ namespace SiMay.Sockets.Tcp.Session if (notify) { - this.NotifyEventHandler?.Invoke(TcpSocketCompletionNotify.OnClosed, this); + this.NotifyEventHandler?.Invoke(TcpSessionNotify.OnClosed, this); } } } diff --git a/SiMay.Sockets.Standard/Tcp/Session/TcpSocketSaeaPackBased.cs b/SiMay.Sockets.Standard/Tcp/Session/TcpSocketSaeaPackBased.cs index 087949d..3356a94 100644 --- a/SiMay.Sockets.Standard/Tcp/Session/TcpSocketSaeaPackBased.cs +++ b/SiMay.Sockets.Standard/Tcp/Session/TcpSocketSaeaPackBased.cs @@ -30,7 +30,7 @@ namespace SiMay.Sockets.Tcp.Session TcpSocketConfigurationBase configuration, SaeaAwaiterPool handlerSaeaPool, SessionPool sessionPool, - NotifyEventHandler notifyEventHandler, + NotifyEventHandler notifyEventHandler, TcpSocketSaeaEngineBased agent) : base(notifyEventHandler, configuration, handlerSaeaPool, sessionPool, agent) { @@ -163,7 +163,7 @@ namespace SiMay.Sockets.Tcp.Session } this.ReceiveBytesTransferred = bytesTransferred; - this.NotifyEventHandler?.Invoke(TcpSocketCompletionNotify.OnDataReceiveing, this); + this.NotifyEventHandler?.Invoke(TcpSessionNotify.OnDataReceiveing, this); _heartTime = DateTime.Now; _packageRecvOffset += bytesTransferred; @@ -187,7 +187,7 @@ namespace SiMay.Sockets.Tcp.Session if (this._isCompress) CompletedBuffer = GZipHelper.Decompress(CompletedBuffer); - this.NotifyEventHandler?.Invoke(TcpSocketCompletionNotify.OnDataReceived, this); + this.NotifyEventHandler?.Invoke(TcpSessionNotify.OnDataReceived, this); } private void EndTransfer(SaeaAwaiter awaiter) @@ -218,7 +218,7 @@ namespace SiMay.Sockets.Tcp.Session this.HandlerSaeaPool.Return(awaiter); this.SendTransferredBytes = a.Saea.Buffer.Length; - this.NotifyEventHandler?.Invoke(TcpSocketCompletionNotify.OnSend, this); + this.NotifyEventHandler?.Invoke(TcpSessionNotify.OnSend, this); }); } @@ -242,6 +242,7 @@ namespace SiMay.Sockets.Tcp.Session { if (Socket != null) { + State = TcpSocketConnectionState.Closed; try { Socket.Shutdown(SocketShutdown.Both); @@ -255,11 +256,9 @@ namespace SiMay.Sockets.Tcp.Session { Socket = null; } - State = TcpSocketConnectionState.Closed; - if (notify) { - this.NotifyEventHandler?.Invoke(TcpSocketCompletionNotify.OnClosed, this); + this.NotifyEventHandler?.Invoke(TcpSessionNotify.OnClosed, this); } } } diff --git a/SiMay.Sockets.Standard/Tcp/Session/TcpSocketSaeaSession.cs b/SiMay.Sockets.Standard/Tcp/Session/TcpSocketSaeaSession.cs index 4781040..e370a0d 100644 --- a/SiMay.Sockets.Standard/Tcp/Session/TcpSocketSaeaSession.cs +++ b/SiMay.Sockets.Standard/Tcp/Session/TcpSocketSaeaSession.cs @@ -15,7 +15,7 @@ namespace SiMay.Sockets.Tcp.Session ///
public abstract class TcpSocketSaeaSession { - protected NotifyEventHandler NotifyEventHandler { get; set; } + protected NotifyEventHandler NotifyEventHandler { get; set; } protected TcpSocketConfigurationBase Configuration { get; set; } @@ -42,7 +42,7 @@ namespace SiMay.Sockets.Tcp.Session public DateTime StartTime { get; protected set; } internal TcpSocketSaeaSession( - NotifyEventHandler notifyEventHandler, + NotifyEventHandler notifyEventHandler, TcpSocketConfigurationBase configuration, SaeaAwaiterPool handlerSaeaPool, SessionPool sessionPool, diff --git a/SiMay.Sockets.Standard/Tcp/TcpSocketCompletionNotify.cs b/SiMay.Sockets.Standard/Tcp/TcpSocketCompletionNotify.cs index e344105..42b5d75 100644 --- a/SiMay.Sockets.Standard/Tcp/TcpSocketCompletionNotify.cs +++ b/SiMay.Sockets.Standard/Tcp/TcpSocketCompletionNotify.cs @@ -5,7 +5,7 @@ using System.Text; namespace SiMay.Sockets.Tcp { - public enum TcpSocketCompletionNotify + public enum TcpSessionNotify { OnConnected, OnSend, diff --git a/SiMay.Sockets.Standard/Tcp/TcpSocketSaeaEngineBased.cs b/SiMay.Sockets.Standard/Tcp/TcpSocketSaeaEngineBased.cs index 968bec7..5947ac3 100644 --- a/SiMay.Sockets.Standard/Tcp/TcpSocketSaeaEngineBased.cs +++ b/SiMay.Sockets.Standard/Tcp/TcpSocketSaeaEngineBased.cs @@ -27,7 +27,7 @@ namespace SiMay.Sockets.Tcp protected TcpSocketSaeaSessionType SaeaSessionType { get; set; } - protected NotifyEventHandler CompletetionNotify { get; set; } + protected NotifyEventHandler CompletetionNotify { get; set; } public int SessionCount { @@ -38,7 +38,7 @@ namespace SiMay.Sockets.Tcp internal TcpSocketSaeaEngineBased( TcpSocketSaeaSessionType saeaSessionType, TcpSocketConfigurationBase configuration, - NotifyEventHandler completetionNotify) + NotifyEventHandler completetionNotify) { TcpSocketSaeaSessions = new List(); HandlerSaeaPool = new SaeaAwaiterPool(); diff --git a/SiMay.Sockets.Standard/Tcp/TcpSocketsFactory.cs b/SiMay.Sockets.Standard/Tcp/TcpSocketsFactory.cs index 88e2dad..b6c26f1 100644 --- a/SiMay.Sockets.Standard/Tcp/TcpSocketsFactory.cs +++ b/SiMay.Sockets.Standard/Tcp/TcpSocketsFactory.cs @@ -16,7 +16,7 @@ namespace SiMay.Sockets.Tcp public static TcpSocketSaeaClientAgent CreateClientAgent( TcpSocketSaeaSessionType saeaSessionType, TcpSocketSaeaClientConfiguration configuration, - NotifyEventHandler completetionNotify) + NotifyEventHandler completetionNotify) { configuration._intervalWhetherService = false; return new TcpSocketSaeaClientAgent(saeaSessionType, configuration, completetionNotify); @@ -25,7 +25,7 @@ namespace SiMay.Sockets.Tcp public static TcpSocketSaeaServer CreateServerAgent( TcpSocketSaeaSessionType saeaSessionType, TcpSocketSaeaServerConfiguration configuration, - NotifyEventHandler completetionNotify) + NotifyEventHandler completetionNotify) { configuration._intervalWhetherService = true; return new TcpSocketSaeaServer(saeaSessionType, configuration, completetionNotify); -- Gitee From b12d85b5bcb3811784984021e5171a517c38f748 Mon Sep 17 00:00:00 2001 From: koko <596461462@qq.com> Date: Sun, 16 Feb 2020 15:46:04 +0800 Subject: [PATCH 09/19] update README.md. --- README.md | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/README.md b/README.md index b85c95a..413aeb8 100644 --- a/README.md +++ b/README.md @@ -9,12 +9,13 @@ - 仅是个人项目,总结在工作中所遇到的有趣技术,新技术,新语法等,系统架构等,经过几次重构,系统相对比较成熟了,决定开源反馈开源社区,希望更多人能和我一起进步,欢迎吐槽改进。 ![主控界面](https://images.gitee.com/uploads/images/2019/0717/225727_cc5c40c8_1654743.jpeg "主控制界面") -![创建服务端](https://images.gitee.com/uploads/images/2019/0717/225801_d0ccad61_1654743.jpeg "创建服务端") +![创建服务端](https://images.gitee.com/uploads/images/2020/0216/154537_c7d2473c_1654743.png "创建服务") ![远程桌面](https://images.gitee.com/uploads/images/2019/0717/225853_2d8f4f8d_1654743.jpeg "远程桌面") ![文件管理](https://images.gitee.com/uploads/images/2019/0717/225829_9fed04ca_1654743.jpeg "文件管理") ![语音传输](https://images.gitee.com/uploads/images/2019/0717/225918_159b8bec_1654743.jpeg "语音传输") ![注册表管理](https://images.gitee.com/uploads/images/2019/0906/221633_6f9559ff_1654743.jpeg "注册表管理") - +![中间服务器](https://images.gitee.com/uploads/images/2020/0216/154108_e5e50552_1654743.png "多对一实时控制") + # 系统项目结构 ### SiMay.Core【公共核心功能】 -- Gitee From 31adbe7d6fa2f34ea2d55c0ef22d56106889633b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E6=96=87=E7=8E=8B=E7=8E=8B?= <596461462@qq.com> Date: Sun, 1 Mar 2020 23:04:06 +0800 Subject: [PATCH 10/19] =?UTF-8?q?6.0=20=E9=92=88=E5=AF=B9=E7=A8=B3?= =?UTF-8?q?=E5=AE=9A=E6=80=A7=E7=9A=84=E6=9B=B4=E6=96=B0?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- README.md | 3 +- SiMay.Basic/SecurityHelper.cs | 25 ++ SiMay.Core/AppJobConstant.cs | 2 + .../{Common => Helper}/ByteConverterHelper.cs | 0 SiMay.Core/{Common => Helper}/FileHelper.cs | 0 SiMay.Core/{Common => Helper}/FileIconUtil.cs | 0 SiMay.Core/Helper/FileTransmissionHelper.cs | 52 ++++ .../{Common => Helper}/GeoLocationHelper.cs | 0 .../{Common => Helper}/PlatformHelper.cs | 0 .../{Common => Helper}/RegValueHelper.cs | 0 .../{Common => Helper}/RegistryKeyHelper.cs | 0 SiMay.Core/MessageHead.cs | 7 +- SiMay.Core/MessageHelper.cs | 13 +- SiMay.Core/Packets/RemoteUpdate/DataPacket.cs | 15 ++ SiMay.Core/ScreenSpy/ScreenSpy.cs | 8 +- SiMay.Core/SiMay.Core.csproj | 16 +- .../SiMay.Net.SessionProvider.Core.csproj | 2 + .../Providers/SessionProvider.cs | 3 +- .../Providers/TcpProxySessionProvider.cs | 11 +- .../Providers/TcpSocketSessionProvider.cs | 11 +- .../TcpSocketSessionContext.cs | 1 + .../SessionProviderService.cs | 37 ++- .../Dispatcher/ApportionDispatcher.cs | 8 +- .../TcpSessionApplicationWorkerConnection.cs | 6 +- .../TcpSessionMainApplicationConnection.cs | 9 +- .../Dispatcher/TcpSessionMainConnection.cs | 11 +- .../DispatcherBase/DispatcherBase.cs | 8 + .../Extension/CreateDispatcherExtension.cs | 4 - .../MainSessionProviderService.cs | 24 +- ...iMay.Net.SessionProviderServiceCore.csproj | 2 + .../ApplicationService/AudioService.cs | 4 +- .../ApplicationService/RemoteUpdateService.cs | 26 ++ .../ApplicationService/ScreenService.cs | 2 +- .../MainService/MainService.cs | 10 +- SiMay.RemoteClient.NewCore/Program.cs | 4 +- .../ServiceBase/ApplicationProtocolService.cs | 8 +- .../SiMay.ServiceCore.csproj | 5 +- .../Packet/{EntityPack.cs => PacketEntity.cs} | 11 +- .../AudioAdapterHandler.cs | 0 .../FileCommon/AwaitAutoResetEvent.cs | 2 +- .../KeyboardAdapterHandler.cs | 0 .../RegistryEditorAdapterHandler.cs | 0 .../RemoteFileAdapterHandler.cs | 12 +- .../RemoteScreenAdapterHandler.cs | 0 .../RemoteUpdateAdapterHandler.cs | 36 +++ .../ShellAdapterHandler.cs | 0 .../StartupAdapterHandler.cs | 0 .../SystemAdapterHandler.cs | 0 .../TcpConnectionAdapterHandler.cs | 0 .../VideoAppAdapterHandler.cs | 0 .../Interface/IApplication.cs | 6 + .../MainApplicationAdapterHandler.cs | 8 + .../SiMay.RemoteControlsCore.csproj | 23 +- .../Application/AudioApplication.Designer.cs | 61 +++-- .../Application/AudioApplication.cs | 53 ++-- .../Application/FileApplication.cs | 5 + .../Application/KeyboardApplication.cs | 5 + .../Application/RegEditorApplication.cs | 5 + .../Application/ScreenApplication.cs | 255 +++++++++++------- .../Application/ShellApplication.cs | 5 + .../Application/StartupApplication.cs | 5 + .../Application/SystemApplication.cs | 5 + .../Application/TcpConnectionApplication.cs | 5 + .../Application/VideoApplication.cs | 76 +++++- SiMay.RemoteMonitor/Helper/KeygenHelper.cs | 35 +++ .../Helper/PCMStreamToWavHelper.cs | 106 ++++++++ .../MainApplication.Designer.cs | 251 +++++++++-------- .../MainApplication/MainApplication.cs | 6 + .../Properties/AssemblyInfo.cs | 4 +- .../SiMay.RemoteMonitor.csproj | 29 +- .../RemoteUpdateApplication.cs | 38 +++ SiMay.RemoteMonitor/Win32Api.cs | 3 + SiMay.RemoteMonitor/packages.config | 6 + SiMay.RemoteMonitorForWeb/Program.cs | 12 + .../SiMay.RemoteMonitorForWeb.csproj | 8 + .../PacketDeserializeSetup.cs | 5 +- .../DynamicMethodMemberAccessor.cs | 5 +- .../SiMay.Sockets.Standard.csproj | 5 +- SiMayRemoteMonitorOS.sln | 19 +- 79 files changed, 1069 insertions(+), 378 deletions(-) create mode 100644 SiMay.Basic/SecurityHelper.cs rename SiMay.Core/{Common => Helper}/ByteConverterHelper.cs (100%) rename SiMay.Core/{Common => Helper}/FileHelper.cs (100%) rename SiMay.Core/{Common => Helper}/FileIconUtil.cs (100%) create mode 100644 SiMay.Core/Helper/FileTransmissionHelper.cs rename SiMay.Core/{Common => Helper}/GeoLocationHelper.cs (100%) rename SiMay.Core/{Common => Helper}/PlatformHelper.cs (100%) rename SiMay.Core/{Common => Helper}/RegValueHelper.cs (100%) rename SiMay.Core/{Common => Helper}/RegistryKeyHelper.cs (100%) create mode 100644 SiMay.Core/Packets/RemoteUpdate/DataPacket.cs create mode 100644 SiMay.RemoteClient.NewCore/ApplicationService/RemoteUpdateService.cs rename SiMay.RemoteClient.NewCore/TrunkService/Packet/{EntityPack.cs => PacketEntity.cs} (66%) rename SiMay.RemoteControlsCore/{ApplicationAdapterHandler => ApplicationAdapterHandlers}/AudioAdapterHandler.cs (100%) rename SiMay.RemoteControlsCore/{ApplicationAdapterHandler => ApplicationAdapterHandlers}/FileCommon/AwaitAutoResetEvent.cs (98%) rename SiMay.RemoteControlsCore/{ApplicationAdapterHandler => ApplicationAdapterHandlers}/KeyboardAdapterHandler.cs (100%) rename SiMay.RemoteControlsCore/{ApplicationAdapterHandler => ApplicationAdapterHandlers}/RegistryEditorAdapterHandler.cs (100%) rename SiMay.RemoteControlsCore/{ApplicationAdapterHandler => ApplicationAdapterHandlers}/RemoteFileAdapterHandler.cs (97%) rename SiMay.RemoteControlsCore/{ApplicationAdapterHandler => ApplicationAdapterHandlers}/RemoteScreenAdapterHandler.cs (100%) create mode 100644 SiMay.RemoteControlsCore/ApplicationAdapterHandlers/RemoteUpdateAdapterHandler.cs rename SiMay.RemoteControlsCore/{ApplicationAdapterHandler => ApplicationAdapterHandlers}/ShellAdapterHandler.cs (100%) rename SiMay.RemoteControlsCore/{ApplicationAdapterHandler => ApplicationAdapterHandlers}/StartupAdapterHandler.cs (100%) rename SiMay.RemoteControlsCore/{ApplicationAdapterHandler => ApplicationAdapterHandlers}/SystemAdapterHandler.cs (100%) rename SiMay.RemoteControlsCore/{ApplicationAdapterHandler => ApplicationAdapterHandlers}/TcpConnectionAdapterHandler.cs (100%) rename SiMay.RemoteControlsCore/{ApplicationAdapterHandler => ApplicationAdapterHandlers}/VideoAppAdapterHandler.cs (100%) create mode 100644 SiMay.RemoteMonitor/Helper/KeygenHelper.cs create mode 100644 SiMay.RemoteMonitor/Helper/PCMStreamToWavHelper.cs create mode 100644 SiMay.RemoteMonitor/UnconventionalApplication/RemoteUpdateApplication.cs create mode 100644 SiMay.RemoteMonitor/packages.config create mode 100644 SiMay.RemoteMonitorForWeb/Program.cs create mode 100644 SiMay.RemoteMonitorForWeb/SiMay.RemoteMonitorForWeb.csproj diff --git a/README.md b/README.md index 413aeb8..038bb71 100644 --- a/README.md +++ b/README.md @@ -104,6 +104,7 @@ 3. 屏幕视图轮播 --2020.1.15 4. Web端主控端 --未实现 5. SOCK5代理,并兼容中间服务转发 -- 未实现 +6. 远程桌面,语音监听,摄像头监控支持录制功能 --2.26 ### 5.0更新 1. 优化了通讯库,支持FULL丶PACK数据处理方式,实现了更友好的配置接口 @@ -112,7 +113,7 @@ 4. 重构代码结构,实现了组件化系统框架,屏蔽了系统底层实现细节,增强了可扩展性 --2019.5.19 5. 远程桌面增加了可视区域扫描算法,仅扫描可视区域变化部分,优化了远程桌面模块,速度更加快了 --2019.4.2 6. 增强系统管理模块,实现了进程实时监控 --8.28 -7. 语音监听,视频监控支持录制功能 --待实现 +7. 语音监听,视频监控支持录制功能 --6.0实现 8. 被控服务实现了以服务方式安装,使用服务方式可实现Session隔离穿透捕获桌面(锁屏,UAC), --11.9 9. 文件管理功文件夹传输重构优化 2019.7.13 10. 系统传输数据消息实体化 -- 2019-6-4 diff --git a/SiMay.Basic/SecurityHelper.cs b/SiMay.Basic/SecurityHelper.cs new file mode 100644 index 0000000..838114b --- /dev/null +++ b/SiMay.Basic/SecurityHelper.cs @@ -0,0 +1,25 @@ +using System; +using System.Collections.Generic; +using System.Security.Cryptography; +using System.Text; + +namespace SiMay.Basic +{ + public class SecurityHelper + { + public static string MD5(string text) + { + using (System.Security.Cryptography.MD5 mi = System.Security.Cryptography.MD5.Create()) + { + byte[] buffer = Encoding.Default.GetBytes(text); + byte[] newBuffer = mi.ComputeHash(buffer); + StringBuilder sb = new StringBuilder(); + for (int i = 0; i < newBuffer.Length; i++) + { + sb.Append(newBuffer[i].ToString("x2")); + } + return sb.ToString(); + } + } + } +} diff --git a/SiMay.Core/AppJobConstant.cs b/SiMay.Core/AppJobConstant.cs index 0e58cc5..bcf570a 100644 --- a/SiMay.Core/AppJobConstant.cs +++ b/SiMay.Core/AppJobConstant.cs @@ -24,5 +24,7 @@ namespace SiMay.Core public const string REMOTE_TCP = "TcpConnectionManagerJob"; public const string REMOTE_VIDEO = "RemoteViedoJob"; + + public const string REMOTE_UPDATE = "RemoteUpdateJob"; } } diff --git a/SiMay.Core/Common/ByteConverterHelper.cs b/SiMay.Core/Helper/ByteConverterHelper.cs similarity index 100% rename from SiMay.Core/Common/ByteConverterHelper.cs rename to SiMay.Core/Helper/ByteConverterHelper.cs diff --git a/SiMay.Core/Common/FileHelper.cs b/SiMay.Core/Helper/FileHelper.cs similarity index 100% rename from SiMay.Core/Common/FileHelper.cs rename to SiMay.Core/Helper/FileHelper.cs diff --git a/SiMay.Core/Common/FileIconUtil.cs b/SiMay.Core/Helper/FileIconUtil.cs similarity index 100% rename from SiMay.Core/Common/FileIconUtil.cs rename to SiMay.Core/Helper/FileIconUtil.cs diff --git a/SiMay.Core/Helper/FileTransmissionHelper.cs b/SiMay.Core/Helper/FileTransmissionHelper.cs new file mode 100644 index 0000000..f59cd5f --- /dev/null +++ b/SiMay.Core/Helper/FileTransmissionHelper.cs @@ -0,0 +1,52 @@ +using System; +using System.Collections.Generic; +using System.IO; +using System.Linq; +using System.Text; +using System.Threading.Tasks; +using SiMay.Basic; + +namespace SiMay.Core.Helper +{ + public class FileTransmissionHelper + { + private const int DefaultBufferSize = 1024 * 100; + + public int BufferSize + { + get + { + return _bufferSize; + } + set + { + if (_bufferSize == value) + return; + _buffer = new byte[value]; + _bufferSize = value; + } + } + + private byte[] _buffer = new byte[DefaultBufferSize]; + private FileStream _fileStream; + private int _bufferSize = DefaultBufferSize; + public FileTransmissionHelper(string fileName, FileMode fileMode) => _fileStream = new FileStream(fileName, fileMode); + + public byte[] Read() + { + int lenght = _fileStream.Read(_buffer, 0, _buffer.Length); + if (lenght < _bufferSize) + return _buffer.Copy(0, lenght); + else + return _buffer; + } + + public void Write(byte[] data) => _fileStream.Write(data, 0, data.Length); + + public void Close() + { + _fileStream.Flush(); + _fileStream.Close(); + } + } +} diff --git a/SiMay.Core/Common/GeoLocationHelper.cs b/SiMay.Core/Helper/GeoLocationHelper.cs similarity index 100% rename from SiMay.Core/Common/GeoLocationHelper.cs rename to SiMay.Core/Helper/GeoLocationHelper.cs diff --git a/SiMay.Core/Common/PlatformHelper.cs b/SiMay.Core/Helper/PlatformHelper.cs similarity index 100% rename from SiMay.Core/Common/PlatformHelper.cs rename to SiMay.Core/Helper/PlatformHelper.cs diff --git a/SiMay.Core/Common/RegValueHelper.cs b/SiMay.Core/Helper/RegValueHelper.cs similarity index 100% rename from SiMay.Core/Common/RegValueHelper.cs rename to SiMay.Core/Helper/RegValueHelper.cs diff --git a/SiMay.Core/Common/RegistryKeyHelper.cs b/SiMay.Core/Helper/RegistryKeyHelper.cs similarity index 100% rename from SiMay.Core/Common/RegistryKeyHelper.cs rename to SiMay.Core/Helper/RegistryKeyHelper.cs diff --git a/SiMay.Core/MessageHead.cs b/SiMay.Core/MessageHead.cs index 1b5cc39..2994501 100644 --- a/SiMay.Core/MessageHead.cs +++ b/SiMay.Core/MessageHead.cs @@ -192,6 +192,11 @@ namespace SiMay.Core S_STARTUP_REMOVE_ITEM, //移除启动项目 C_STARTUP_LIST = 2000, //启动项列表 - C_STARTUP_OPER_RESPONSE //操作结果 + C_STARTUP_OPER_RESPONSE, //操作结果 + + C_REMOTE_UPDATE_READY = 2000, //远程就绪 + C_REMOTE_UPDATE_NEXT_DATA, //获取下一个文件数据 + + S_REMOTE_UPDATE_DATA, //文件数据 } } \ No newline at end of file diff --git a/SiMay.Core/MessageHelper.cs b/SiMay.Core/MessageHelper.cs index cdc3e91..a665c82 100644 --- a/SiMay.Core/MessageHelper.cs +++ b/SiMay.Core/MessageHelper.cs @@ -1,4 +1,5 @@ using System; +using System.IO; using SiMay.Core.Extensions; using static SiMay.Serialize.Standard.PacketSerializeHelper; @@ -99,8 +100,16 @@ namespace SiMay.Core public static T GetMessageEntity(this byte[] data) where T : new() { - var entity = DeserializePacket(GetMessagePayload(data)); - return entity; + try + { + var entity = DeserializePacket(GetMessagePayload(data)); + return entity; + } + catch + { + File.WriteAllBytes(Path.Combine(Environment.CurrentDirectory, $"{typeof(T).FullName}_{DateTime.Now.ToFileTime()}"), data); + } + return default; } } } \ No newline at end of file diff --git a/SiMay.Core/Packets/RemoteUpdate/DataPacket.cs b/SiMay.Core/Packets/RemoteUpdate/DataPacket.cs new file mode 100644 index 0000000..f4da2f0 --- /dev/null +++ b/SiMay.Core/Packets/RemoteUpdate/DataPacket.cs @@ -0,0 +1,15 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace SiMay.Core.Packets.RemoteUpdate +{ + public class DataPacket + { + public int TotalSize { get; set; } + + public byte[] Data { get; set; } + } +} diff --git a/SiMay.Core/ScreenSpy/ScreenSpy.cs b/SiMay.Core/ScreenSpy/ScreenSpy.cs index 5435729..afef702 100644 --- a/SiMay.Core/ScreenSpy/ScreenSpy.cs +++ b/SiMay.Core/ScreenSpy/ScreenSpy.cs @@ -81,9 +81,11 @@ namespace SiMay.Core.ScreenSpy public void FindDifferences(bool hotRegionScan, Rectangle rect) { + var previousFrame = _capturer.PreviousFrame; + _capturer.Capture(); + var currenFrame = _capturer.CurrentFrame; - var previousFrame = _capturer.PreviousFrame; if (!hotRegionScan) _capturer.Size = new Size(rect.Width, rect.Height); @@ -171,9 +173,11 @@ namespace SiMay.Core.ScreenSpy public void FullFindDifferences(bool hotRegionScan, Rectangle rect) { + var previousFrame = _capturer.PreviousFrame; + _capturer.Capture(); + var currenFrame = _capturer.CurrentFrame; - var previousFrame = _capturer.PreviousFrame; if (!hotRegionScan) _capturer.Size = new Size(rect.Width, rect.Height); diff --git a/SiMay.Core/SiMay.Core.csproj b/SiMay.Core/SiMay.Core.csproj index eab07be..42a241c 100644 --- a/SiMay.Core/SiMay.Core.csproj +++ b/SiMay.Core/SiMay.Core.csproj @@ -51,12 +51,13 @@ - - - - - - + + + + + + + @@ -71,7 +72,7 @@ - + @@ -130,6 +131,7 @@ + diff --git a/SiMay.Net.SessionProvider.Core/SiMay.Net.SessionProvider.Core.csproj b/SiMay.Net.SessionProvider.Core/SiMay.Net.SessionProvider.Core.csproj index 1806e6c..7dea9a3 100644 --- a/SiMay.Net.SessionProvider.Core/SiMay.Net.SessionProvider.Core.csproj +++ b/SiMay.Net.SessionProvider.Core/SiMay.Net.SessionProvider.Core.csproj @@ -2,6 +2,8 @@ netstandard2.0 + false + false diff --git a/SiMay.Net.SessionProvider/Providers/SessionProvider.cs b/SiMay.Net.SessionProvider/Providers/SessionProvider.cs index 3ca847e..7f54be0 100644 --- a/SiMay.Net.SessionProvider/Providers/SessionProvider.cs +++ b/SiMay.Net.SessionProvider/Providers/SessionProvider.cs @@ -24,7 +24,8 @@ namespace SiMay.Net.SessionProvider /// 广播发送 ///
/// - public abstract void BroadcastAsync(byte[] data); + public virtual void BroadcastAsync(byte[] data) + => BroadcastAsync(data, 0, data.Length); /// /// 广播发送 diff --git a/SiMay.Net.SessionProvider/Providers/TcpProxySessionProvider.cs b/SiMay.Net.SessionProvider/Providers/TcpProxySessionProvider.cs index b6f1ab8..b17d579 100644 --- a/SiMay.Net.SessionProvider/Providers/TcpProxySessionProvider.cs +++ b/SiMay.Net.SessionProvider/Providers/TcpProxySessionProvider.cs @@ -190,9 +190,7 @@ namespace SiMay.Net.SessionProvider.Providers }; } else if (session.AppTokens.IsNull() && this._currentState == CHANNEL_LOGIN) - { return; - } var type = session.AppTokens[SysContanct.INDEX_WORKTYPE].ConvertTo(); if (type == ConnectionWorkType.MainApplicationConnection) @@ -211,7 +209,7 @@ namespace SiMay.Net.SessionProvider.Providers { foreach (var proxySession in _proxySessions.Select(c => c.Value)) this.SessionNotify(proxySession, TcpSessionNotify.OnClosed); - this._proxySessions.Clear(); + this._proxySessions.Clear(); } if (!_wetherLogOut) @@ -234,7 +232,7 @@ namespace SiMay.Net.SessionProvider.Providers { var sessionContext = session.AppTokens[SysContanct.INDEX_WORKER].ConvertTo(); this.SessionNotify(sessionContext, TcpSessionNotify.OnClosed); - this._proxySessions.Remove(sessionContext.GetHashCode()); + this._proxySessions.Remove(sessionContext.GetHashCode()); } } } @@ -243,11 +241,6 @@ namespace SiMay.Net.SessionProvider.Providers { this._clientAgent.ConnectToServer(ApplicationConfiguartion.Options.ServiceIPEndPoint); } - public override void BroadcastAsync(byte[] data) - { - foreach (var session in this._proxySessions.Select(c => c.Value)) - session.SendAsync(data); - } public override void BroadcastAsync(byte[] data, int offset, int lenght) { diff --git a/SiMay.Net.SessionProvider/Providers/TcpSocketSessionProvider.cs b/SiMay.Net.SessionProvider/Providers/TcpSocketSessionProvider.cs index ae2ad30..208b0ab 100644 --- a/SiMay.Net.SessionProvider/Providers/TcpSocketSessionProvider.cs +++ b/SiMay.Net.SessionProvider/Providers/TcpSocketSessionProvider.cs @@ -15,7 +15,6 @@ namespace SiMay.Net.SessionProvider.Providers internal TcpSocketSessionProvider(SessionProviderOptions options) { ApplicationConfiguartion.SetOptions(options); - ; var serverConfig = new TcpSocketSaeaServerConfiguration(); serverConfig.AppKeepAlive = true; @@ -29,9 +28,6 @@ namespace SiMay.Net.SessionProvider.Providers case TcpSessionNotify.OnConnected: SessionProviderContext sessionBased = new TcpSocketSessionContext(session); - session.AppTokens = new object[] { - sessionBased - }; this.SessionNotify(sessionBased, TcpSessionNotify.OnConnected); break; case TcpSessionNotify.OnSend: @@ -52,12 +48,7 @@ namespace SiMay.Net.SessionProvider.Providers }); } - public override void StartSerivce() - { - _server.Listen(ApplicationConfiguartion.Options.ServiceIPEndPoint); - } - - public override void BroadcastAsync(byte[] data) => _server.BroadcastAsync(data); + public override void StartSerivce() => _server.Listen(ApplicationConfiguartion.Options.ServiceIPEndPoint); public override void BroadcastAsync(byte[] data, int offset, int lenght) => _server.BroadcastAsync(data, offset, lenght); diff --git a/SiMay.Net.SessionProvider/TcpSessionConnection/TcpSocketSessionContext.cs b/SiMay.Net.SessionProvider/TcpSessionConnection/TcpSocketSessionContext.cs index 3de8bdc..36cf6e0 100644 --- a/SiMay.Net.SessionProvider/TcpSessionConnection/TcpSocketSessionContext.cs +++ b/SiMay.Net.SessionProvider/TcpSessionConnection/TcpSocketSessionContext.cs @@ -14,6 +14,7 @@ namespace SiMay.Net.SessionProvider public TcpSocketSessionContext(TcpSocketSaeaSession session) { CurrentSession = session; + session.AppTokens = new object[] { this }; } /// /// 发送长度 diff --git a/SiMay.Net.SessionProviderService/SessionProviderService.cs b/SiMay.Net.SessionProviderService/SessionProviderService.cs index 9ca6e9b..8678fc1 100644 --- a/SiMay.Net.SessionProviderService/SessionProviderService.cs +++ b/SiMay.Net.SessionProviderService/SessionProviderService.cs @@ -36,12 +36,6 @@ namespace SiMay.Net.SessionProviderService SystemOptionsDialog dlg = new SystemOptionsDialog(); dlg.ShowDialog(); break; - case IDM_RUNLOG: - if (File.Exists("Run.log")) - { - Process.Start("Run.log"); - } - break; } } base.WndProc(ref m); @@ -61,7 +55,6 @@ namespace SiMay.Net.SessionProviderService InsertMenu(sysMenuHandle, 7, MF_SEPARATOR, 0, null); InsertMenu(sysMenuHandle, 8, MF_BYPOSITION, IDM_OPTIONS, "系统设置"); - InsertMenu(sysMenuHandle, 9, MF_BYPOSITION, IDM_RUNLOG, "运行日志"); this._log_imgList = new ImageList(); this._log_imgList.Images.Add("ok", Resources.ok); @@ -87,10 +80,10 @@ namespace SiMay.Net.SessionProviderService _sessionProviderService.LogOutputEventHandler += LogOutputEventHandler; var startResult = _sessionProviderService.StartService(new StartServiceOptions() { - AccessKey = ApplicationConfiguration.AccessKey, LocalAddress = ApplicationConfiguration.LoalAddress, ServicePort = ApplicationConfiguration.Port, MaxPacketSize = 1024 * 1024 * 2, + AccessKey = ApplicationConfiguration.AccessKey, MainAppAccessKey = ApplicationConfiguration.MainAppAccessKey, MainApplicationAllowAccessId = !ApplicationConfiguration.AccessIds.IsNullOrEmpty() ? ApplicationConfiguration.AccessIds.Split(',').Select(c => long.Parse(c)).ToArray() : new long[0], MainApplicationAnonyMous = ApplicationConfiguration.AnonyMous @@ -106,8 +99,8 @@ namespace SiMay.Net.SessionProviderService dispatcher.LogOutputEventHandler -= LogOutputEventHandler; - _channelCount--; - lableConnectionCount.Text = _channelCount.ToString(); + this._channelCount--; + this.lableConnectionCount.Text = _channelCount.ToString(); } private void OnConnectedEventHandler(TcpSessionChannelDispatcher dispatcher) @@ -115,16 +108,18 @@ namespace SiMay.Net.SessionProviderService var viewItem = new ChannelViewItem(dispatcher); this.channelListView.Items.Add(viewItem); dispatcher.LogOutputEventHandler += LogOutputEventHandler; - _channelCount++; - lableConnectionCount.Text = _channelCount.ToString(); + this._channelCount++; + this.lableConnectionCount.Text = _channelCount.ToString(); } private void LogOutputEventHandler(DispatcherBase dispatcher, LogOutLevelType levelType, string log) => this.Log(levelType, log); private void Log(LogOutLevelType levelType, string log) { - var viewItem = new ListViewItem(); + if (this.logList.Items.Count > 500) + CleanViewLog(); + var viewItem = new ListViewItem(); viewItem.Text = DateTime.Now.ToString(); viewItem.SubItems.Add(log); switch (levelType) @@ -147,17 +142,17 @@ namespace SiMay.Net.SessionProviderService foreach (ChannelViewItem item in channelListView.Items) { item.SetVelocityText(item.SendStreamLength, item.ReceiveStreamLength); - _uploadTransferBytes += item.SendStreamLength; - _receiveTransferBytes += item.ReceiveStreamLength; + this._uploadTransferBytes += item.SendStreamLength; + this._receiveTransferBytes += item.ReceiveStreamLength; item.SendStreamLength = 0; item.ReceiveStreamLength = 0; } - lbUpload.Text = (_uploadTransferBytes / 1024).ToString("0.00"); - lbReceive.Text = (_receiveTransferBytes / 1024).ToString("0.00"); - _uploadTransferBytes = 0; - _receiveTransferBytes = 0; + this.lbUpload.Text = (_uploadTransferBytes / 1024).ToString("0.00"); + this.lbReceive.Text = (_receiveTransferBytes / 1024).ToString("0.00"); + this._uploadTransferBytes = 0; + this._receiveTransferBytes = 0; } private void CleanViewLog() @@ -173,13 +168,13 @@ namespace SiMay.Net.SessionProviderService private void toolStripMenuItem1_Click(object sender, EventArgs e) { - if (logList.SelectedItems.Count != 0) + if (this.logList.SelectedItems.Count != 0) Clipboard.SetText(string.Join(",", logList.Items[logList.SelectedItems.FristOrDefault().Index].SubItems.Select(c => c.Text))); } private void toolStripMenuItem2_Click(object sender, EventArgs e) { - if (logList.SelectedItems.Count != 0) + if (this.logList.SelectedItems.Count != 0) { int Index = logList.SelectedItems[0].Index; if (Index >= 1) diff --git a/SiMay.Net.SessionProviderServiceCore/Dispatcher/ApportionDispatcher.cs b/SiMay.Net.SessionProviderServiceCore/Dispatcher/ApportionDispatcher.cs index d1191fb..6eb7d6f 100644 --- a/SiMay.Net.SessionProviderServiceCore/Dispatcher/ApportionDispatcher.cs +++ b/SiMay.Net.SessionProviderServiceCore/Dispatcher/ApportionDispatcher.cs @@ -30,8 +30,8 @@ namespace SiMay.Net.SessionProviderServiceCore if (packageLen < 0 || packageLen > ApplicationConfiguartion.Options.MaxPacketSize || packageLen < 25) //数据不合法 或 小于大概ack固定长度 { - this.CloseSession(); this.Log(LogOutLevelType.Error, $"Type:{ConnectionWorkType.ToString()} 长度不合法!"); + this.CloseSession(); return; } @@ -54,10 +54,10 @@ namespace SiMay.Net.SessionProviderServiceCore this.ApportionTypeHandlerEvent?.Invoke(this, (ConnectionWorkType)ack.Type); else { - var data = MessageHelper.CopyMessageHeadTo(MessageHead.MID_ACCESS_KEY_WRONG); - this.CurrentSession.SendAsync(data.BuilderHeadPacket()); - this.CloseSession(); + var midData = MessageHelper.CopyMessageHeadTo(MessageHead.MID_ACCESS_KEY_WRONG); + this.CurrentSession.SendAsync(midData.BuilderHeadPacket()); this.Log(LogOutLevelType.Debug, $"Type:{((ConnectionWorkType)ack.Type).ToString()} AccessId:{ack.AccessId} 或AccessKey:{ack.AccessKey} 验证失败,登陆不成功!"); + this.CloseSession(); } } else diff --git a/SiMay.Net.SessionProviderServiceCore/Dispatcher/TcpSessionApplicationWorkerConnection.cs b/SiMay.Net.SessionProviderServiceCore/Dispatcher/TcpSessionApplicationWorkerConnection.cs index 1b631a3..c2cc074 100644 --- a/SiMay.Net.SessionProviderServiceCore/Dispatcher/TcpSessionApplicationWorkerConnection.cs +++ b/SiMay.Net.SessionProviderServiceCore/Dispatcher/TcpSessionApplicationWorkerConnection.cs @@ -2,6 +2,7 @@ using System.Collections.Generic; using System.Text; using SiMay.Net.SessionProvider.Core; +using SiMay.Sockets.Tcp; namespace SiMay.Net.SessionProviderServiceCore { @@ -22,6 +23,9 @@ namespace SiMay.Net.SessionProviderServiceCore _targetConnection = targetConnection; targetConnection.Join(this); } + + public override void OnMessageBefore(byte[] data) => this._targetConnection.SendTo(data); + public override void OnMessage() { base.OnMessage(); @@ -33,7 +37,7 @@ namespace SiMay.Net.SessionProviderServiceCore } public override void OnClosed() { - if (_targetConnection.CurrentSession.State == Sockets.Tcp.TcpSocketConnectionState.Closed) + if (_targetConnection.CurrentSession.State == TcpSocketConnectionState.Closed) return; _targetConnection.CloseSession(); ListByteBuffer.Clear(); diff --git a/SiMay.Net.SessionProviderServiceCore/Dispatcher/TcpSessionMainApplicationConnection.cs b/SiMay.Net.SessionProviderServiceCore/Dispatcher/TcpSessionMainApplicationConnection.cs index b095d3a..b716e7f 100644 --- a/SiMay.Net.SessionProviderServiceCore/Dispatcher/TcpSessionMainApplicationConnection.cs +++ b/SiMay.Net.SessionProviderServiceCore/Dispatcher/TcpSessionMainApplicationConnection.cs @@ -16,10 +16,7 @@ namespace SiMay.Net.SessionProviderServiceCore public override ConnectionWorkType ConnectionWorkType => ConnectionWorkType.MainApplicationConnection; private readonly IDictionary _dispatchers; - public TcpSessionMainApplicationConnection(IDictionary dispatchers) - { - _dispatchers = dispatchers; - } + public TcpSessionMainApplicationConnection(IDictionary dispatchers) => _dispatchers = dispatchers; public override void OnMessage() { @@ -44,9 +41,9 @@ namespace SiMay.Net.SessionProviderServiceCore if (packageLen + defineHeadSize > ListByteBuffer.Count) return; - byte[] data = ListByteBuffer.GetRange(defineHeadSize, packageLen).ToArray(); + byte[] mainAppMessageData = ListByteBuffer.GetRange(defineHeadSize, packageLen).ToArray(); - this.MessageCompletedHandler(data); + this.MessageCompletedHandler(mainAppMessageData); ListByteBuffer.RemoveRange(0, packageLen + defineHeadSize); } while (ListByteBuffer.Count > defineHeadSize); diff --git a/SiMay.Net.SessionProviderServiceCore/Dispatcher/TcpSessionMainConnection.cs b/SiMay.Net.SessionProviderServiceCore/Dispatcher/TcpSessionMainConnection.cs index cc51009..d3dfc37 100644 --- a/SiMay.Net.SessionProviderServiceCore/Dispatcher/TcpSessionMainConnection.cs +++ b/SiMay.Net.SessionProviderServiceCore/Dispatcher/TcpSessionMainConnection.cs @@ -12,10 +12,7 @@ namespace SiMay.Net.SessionProviderServiceCore private readonly object _sendLock = new object(); private readonly IDictionary _dispatchers; - public TcpSessionMainConnection(IDictionary dispatchers) - { - _dispatchers = dispatchers; - } + public TcpSessionMainConnection(IDictionary dispatchers) => _dispatchers = dispatchers; public byte[] ACKPacketData { get; set; } @@ -48,9 +45,9 @@ namespace SiMay.Net.SessionProviderServiceCore this._transpondOffset += calculateOffsetLength; if (calculateOffsetLength == 0) { - this._accessId = null; this._packageLength = null; this._lastChannelCreatedTime = null;continue; + this._accessId = null; this._packageLength = null; this._lastChannelCreatedTime = null; continue; } - var data = ListByteBuffer.GetRange(0, calculateOffsetLength).ToArray(); + var waitTranspondData = ListByteBuffer.GetRange(0, calculateOffsetLength).ToArray(); TcpSessionChannelDispatcher dispatcher; if (_dispatchers.TryGetValue(_accessId.Value, out dispatcher) && dispatcher is TcpSessionMainApplicationConnection mainApplicationConnection) { @@ -65,7 +62,7 @@ namespace SiMay.Net.SessionProviderServiceCore { AccessId = dispatcher.DispatcherId, DispatcherId = this.DispatcherId, - Data = data + Data = waitTranspondData })); } else diff --git a/SiMay.Net.SessionProviderServiceCore/DispatcherBase/DispatcherBase.cs b/SiMay.Net.SessionProviderServiceCore/DispatcherBase/DispatcherBase.cs index f26d5c0..0f5d49c 100644 --- a/SiMay.Net.SessionProviderServiceCore/DispatcherBase/DispatcherBase.cs +++ b/SiMay.Net.SessionProviderServiceCore/DispatcherBase/DispatcherBase.cs @@ -92,11 +92,19 @@ namespace SiMay.Net.SessionProviderServiceCore CurrentSession.Close(true); } + /// + /// 消息处理前 + /// + /// + public virtual void OnMessageBefore(byte[] data) + => ListByteBuffer.AddRange(data); + /// /// 触发消息处理 /// public abstract void OnMessage(); + /// /// 会话关闭 /// diff --git a/SiMay.Net.SessionProviderServiceCore/Extension/CreateDispatcherExtension.cs b/SiMay.Net.SessionProviderServiceCore/Extension/CreateDispatcherExtension.cs index a8bfbc1..38a81bc 100644 --- a/SiMay.Net.SessionProviderServiceCore/Extension/CreateDispatcherExtension.cs +++ b/SiMay.Net.SessionProviderServiceCore/Extension/CreateDispatcherExtension.cs @@ -43,10 +43,6 @@ namespace SiMay.Net.SessionProviderServiceCore var workerConnection = new TcpSessionApplicationWorkerConnection(); workerConnection.ConnectionWorkType = workType; workerConnection.SetSession(apportionDispatcher.CurrentSession); - - var bufferData = apportionDispatcher.ListByteBuffer.ToArray(); - if (bufferData.Length > 0)//如缓冲区有数据,则处理消息 - workerConnection.ListByteBuffer.AddRange(bufferData); return workerConnection; } } diff --git a/SiMay.Net.SessionProviderServiceCore/MainSessionProviderService.cs b/SiMay.Net.SessionProviderServiceCore/MainSessionProviderService.cs index 826f16d..b9fe1a3 100644 --- a/SiMay.Net.SessionProviderServiceCore/MainSessionProviderService.cs +++ b/SiMay.Net.SessionProviderServiceCore/MainSessionProviderService.cs @@ -105,7 +105,7 @@ namespace SiMay.Net.SessionProviderServiceCore { byte[] data = session.CompletedBuffer.Copy(0, session.ReceiveBytesTransferred); var dispatcher = session.AppTokens[SysContanct.INDEX_WORKER].ConvertTo(); - dispatcher.ListByteBuffer.AddRange(data); + dispatcher.OnMessageBefore(data); dispatcher.OnMessage(); } @@ -136,6 +136,13 @@ namespace SiMay.Net.SessionProviderServiceCore if (_dispatchers.ContainsKey(closedDispatcher.DispatcherId)) _dispatchers.Remove(closedDispatcher.DispatcherId); + if (closedDispatcher is ApportionDispatcher ofclosedApportionDispatcher) + { + ofclosedApportionDispatcher.ApportionTypeHandlerEvent -= ApportionTypeHandlerEvent; + ofclosedApportionDispatcher.LogOutputEventHandler -= ApportionDispatcher_LogOutputEventHandler; + ofclosedApportionDispatcher.Dispose(); + } + if (closedDispatcher is TcpSessionChannelDispatcher tcpSessionChannelDispatcher) this.OnClosedEventHandler?.Invoke(tcpSessionChannelDispatcher); @@ -217,7 +224,15 @@ namespace SiMay.Net.SessionProviderServiceCore private void ApplicationServiceConnect(ApportionDispatcher apportionDispatcher) { var appWorkerConnectionDispatcher = apportionDispatcher.CreateApplicationWorkerChannelDispatcher(_dispatchers, ConnectionWorkType.ApplicationServiceConnection); + appWorkerConnectionDispatcher.ListByteBuffer.AddRange(apportionDispatcher.GetACKPacketData().BuilderHeadPacket()); + + if (apportionDispatcher.ListByteBuffer.Count > 0) + { + var bufferData = apportionDispatcher.ListByteBuffer.ToArray(); + appWorkerConnectionDispatcher.ListByteBuffer.AddRange(bufferData); + } + this._dispatchers.Add(appWorkerConnectionDispatcher.DispatcherId, appWorkerConnectionDispatcher); this._appServiceChannels.Add(new Tuple(apportionDispatcher.GetAccessId(), appWorkerConnectionDispatcher.DispatcherId)); this.OnConnectedEventHandler?.Invoke(appWorkerConnectionDispatcher); @@ -244,6 +259,13 @@ namespace SiMay.Net.SessionProviderServiceCore this._appServiceChannels.Remove(serviceWorkerChannelItem); var serviceChannelDispatcher = dispatcher.ConvertTo(); var appChannelDispatcher = apportionDispatcher.CreateApplicationWorkerChannelDispatcher(_dispatchers, ConnectionWorkType.ApplicationConnection); + + if (apportionDispatcher.ListByteBuffer.Count > 0) + { + var bufferData = apportionDispatcher.ListByteBuffer.ToArray(); + appChannelDispatcher.ListByteBuffer.AddRange(bufferData); + } + this._dispatchers.Add(appChannelDispatcher.DispatcherId, appChannelDispatcher); this.OnConnectedEventHandler?.Invoke(appChannelDispatcher); diff --git a/SiMay.Net.SessionProviderServiceCore/SiMay.Net.SessionProviderServiceCore.csproj b/SiMay.Net.SessionProviderServiceCore/SiMay.Net.SessionProviderServiceCore.csproj index ddd3503..b2fff1c 100644 --- a/SiMay.Net.SessionProviderServiceCore/SiMay.Net.SessionProviderServiceCore.csproj +++ b/SiMay.Net.SessionProviderServiceCore/SiMay.Net.SessionProviderServiceCore.csproj @@ -2,6 +2,8 @@ netstandard2.0 + false + false diff --git a/SiMay.RemoteClient.NewCore/ApplicationService/AudioService.cs b/SiMay.RemoteClient.NewCore/ApplicationService/AudioService.cs index c32d429..bb9d8e4 100644 --- a/SiMay.RemoteClient.NewCore/ApplicationService/AudioService.cs +++ b/SiMay.RemoteClient.NewCore/ApplicationService/AudioService.cs @@ -65,8 +65,8 @@ namespace SiMay.ServiceCore SendTo(CurrentSession, MessageHead.C_AUDIO_DEVICE_OPENSTATE, new AudioDeviceStatesPack() { - PlayerEnable = outDeviceOpen == 0 ? true : false, - RecordEnable = inDeviceOpen == 0 ? true : false + PlayerEnable = outDeviceOpen == 0, + RecordEnable = inDeviceOpen == 0 }); } diff --git a/SiMay.RemoteClient.NewCore/ApplicationService/RemoteUpdateService.cs b/SiMay.RemoteClient.NewCore/ApplicationService/RemoteUpdateService.cs new file mode 100644 index 0000000..129d084 --- /dev/null +++ b/SiMay.RemoteClient.NewCore/ApplicationService/RemoteUpdateService.cs @@ -0,0 +1,26 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; +using SiMay.Core; +using SiMay.ServiceCore.Attributes; +using SiMay.Sockets.Tcp.Session; + +namespace SiMay.ServiceCore.ApplicationService +{ + [ServiceName("远程更新服务")] + [ServiceKey(AppJobConstant.REMOTE_UPDATE)] + public class RemoteUpdateService : ApplicationRemoteService + { + public override void SessionClosed() + { + throw new NotImplementedException(); + } + + public override void SessionInited(TcpSocketSaeaSession session) + { + + } + } +} diff --git a/SiMay.RemoteClient.NewCore/ApplicationService/ScreenService.cs b/SiMay.RemoteClient.NewCore/ApplicationService/ScreenService.cs index 369d432..d3e27d2 100644 --- a/SiMay.RemoteClient.NewCore/ApplicationService/ScreenService.cs +++ b/SiMay.RemoteClient.NewCore/ApplicationService/ScreenService.cs @@ -141,7 +141,7 @@ namespace SiMay.ServiceCore { var rect = GetMessageEntity(session); //根据监控模式使用热区域扫描 - bool ishotRegtionScan = rect.CtrlMode == 1 ? true : false; + bool ishotRegtionScan = false;// rect.CtrlMode == 1 ? true : false; if (_hasSystemAuthor) Win32Interop.SwitchToInputDesktop(); diff --git a/SiMay.RemoteClient.NewCore/MainService/MainService.cs b/SiMay.RemoteClient.NewCore/MainService/MainService.cs index 1802e21..875ade9 100644 --- a/SiMay.RemoteClient.NewCore/MainService/MainService.cs +++ b/SiMay.RemoteClient.NewCore/MainService/MainService.cs @@ -481,8 +481,6 @@ namespace SiMay.ServiceCore.MainService { ThreadHelper.ThreadPoolStart(c => { - ThreadLocalAccessId.Value = GetAccessId(session); - var getframe = GetMessageEntity(session); if (getframe.Width == 0 || getframe.Height == 0 || getframe.TimeSpan == 0 || getframe.TimeSpan < 50) return; @@ -523,10 +521,8 @@ namespace SiMay.ServiceCore.MainService SendTo(session, MessageHead.C_MAIN_DESKTOPRECORD_OPEN, Environment.MachineName); } [PacketHandler(MessageHead.S_MAIN_DESKTOPRECORD_CLOSE)] - private void DesktopRecordClose(TcpSocketSaeaSession session) - { - AppConfiguartion.IsScreenRecord = false; - } + private void DesktopRecordClose(TcpSocketSaeaSession session) + => AppConfiguartion.IsScreenRecord = false; /// /// 远程创建屏幕墙屏幕视图 @@ -609,7 +605,7 @@ namespace SiMay.ServiceCore.MainService var loginPack = new LoginPack(); loginPack.IPV4 = SystemInfoHelper.GetLocalIPV4(); - loginPack.MachineName = Environment.MachineName ?? ""; + loginPack.MachineName = Environment.MachineName ?? string.Empty; loginPack.Remark = remarkInfomation; loginPack.ProcessorCount = Environment.ProcessorCount; loginPack.ProcessorInfo = SystemInfoHelper.GetMyCpuInfo; diff --git a/SiMay.RemoteClient.NewCore/Program.cs b/SiMay.RemoteClient.NewCore/Program.cs index 1eacf96..c77a00e 100644 --- a/SiMay.RemoteClient.NewCore/Program.cs +++ b/SiMay.RemoteClient.NewCore/Program.cs @@ -71,8 +71,8 @@ namespace SiMay.ServiceCore var startParameter = new StartParameterEx() { Host = "94.191.115.121", + //Port = 520, Port = 522, - //Port = 522, GroupName = "默认分组", RemarkInformation = "SiMayService", IsHide = false, @@ -106,7 +106,7 @@ namespace SiMay.ServiceCore startParameter.IsHide = options.IsHide; startParameter.AccessKey = options.AccessKey; startParameter.SessionMode = options.SessionMode; - startParameter.UniqueId = options.Id; + startParameter.UniqueId = options.Id + $"_{Environment.MachineName}"; startParameter.IsMutex = options.IsMutex; startParameter.GroupName = options.GroupName; startParameter.InstallService = options.InstallService; diff --git a/SiMay.RemoteClient.NewCore/ServiceBase/ApplicationProtocolService.cs b/SiMay.RemoteClient.NewCore/ServiceBase/ApplicationProtocolService.cs index c88e06b..fe9ff5e 100644 --- a/SiMay.RemoteClient.NewCore/ServiceBase/ApplicationProtocolService.cs +++ b/SiMay.RemoteClient.NewCore/ServiceBase/ApplicationProtocolService.cs @@ -12,7 +12,6 @@ namespace SiMay.ServiceCore /// public abstract class ApplicationProtocolService : ApplicationServiceBase { - protected ThreadLocal ThreadLocalAccessId = new ThreadLocal(); /// /// 数据处理绑定 /// @@ -42,8 +41,7 @@ namespace SiMay.ServiceCore protected virtual void SendToBefore(TcpSocketSaeaSession session, byte[] data) { - var accessId = ThreadLocalAccessId.IsValueCreated ? ThreadLocalAccessId.Value : GetAccessId(session); - Console.WriteLine("ID:" + accessId); + var accessId = GetAccessId(session); SendTo(session, WrapAccessId(GZipHelper.Compress(data, 0, data.Length), accessId)); } @@ -83,9 +81,7 @@ namespace SiMay.ServiceCore private byte[] TakeHeadAndMessage(TcpSocketSaeaSession session) { - var length = session.CompletedBuffer.Length - sizeof(long); - var bytes = new byte[length]; - Array.Copy(session.CompletedBuffer, sizeof(long), bytes, 0, length); + var bytes = session.CompletedBuffer.Copy(sizeof(long), session.CompletedBuffer.Length - sizeof(long)); return GZipHelper.Decompress(bytes); } diff --git a/SiMay.RemoteClient.NewCore/SiMay.ServiceCore.csproj b/SiMay.RemoteClient.NewCore/SiMay.ServiceCore.csproj index 242962a..44862e8 100644 --- a/SiMay.RemoteClient.NewCore/SiMay.ServiceCore.csproj +++ b/SiMay.RemoteClient.NewCore/SiMay.ServiceCore.csproj @@ -57,7 +57,7 @@ true - bin\x64\Debug\ + ..\Bin\dat\ DEBUG;TRACE full x64 @@ -117,6 +117,7 @@ + @@ -151,7 +152,7 @@ - + Component diff --git a/SiMay.RemoteClient.NewCore/TrunkService/Packet/EntityPack.cs b/SiMay.RemoteClient.NewCore/TrunkService/Packet/PacketEntity.cs similarity index 66% rename from SiMay.RemoteClient.NewCore/TrunkService/Packet/EntityPack.cs rename to SiMay.RemoteClient.NewCore/TrunkService/Packet/PacketEntity.cs index 845b27c..19b6916 100644 --- a/SiMay.RemoteClient.NewCore/TrunkService/Packet/EntityPack.cs +++ b/SiMay.RemoteClient.NewCore/TrunkService/Packet/PacketEntity.cs @@ -1,26 +1,27 @@ -using System; +using SiMay.ReflectCache; +using System; using System.Collections.Generic; using System.Linq; using System.Text; namespace SiMay.ServiceCore { - public class ActivePack + public class ActivePack : EntitySerializerBase { public int SessionId { get; set; } } - public class SessionStatusPack + public class SessionStatusPack : EntitySerializerBase { public SessionItem[] Sessions { get; set; } } - public class CreateUserProcessPack + public class CreateUserProcessPack : EntitySerializerBase { public int SessionId { get; set; } } - public class SessionItem + public class SessionItem : EntitySerializerBase { public string UserName { get; set; } public int SessionId { get; set; } diff --git a/SiMay.RemoteControlsCore/ApplicationAdapterHandler/AudioAdapterHandler.cs b/SiMay.RemoteControlsCore/ApplicationAdapterHandlers/AudioAdapterHandler.cs similarity index 100% rename from SiMay.RemoteControlsCore/ApplicationAdapterHandler/AudioAdapterHandler.cs rename to SiMay.RemoteControlsCore/ApplicationAdapterHandlers/AudioAdapterHandler.cs diff --git a/SiMay.RemoteControlsCore/ApplicationAdapterHandler/FileCommon/AwaitAutoResetEvent.cs b/SiMay.RemoteControlsCore/ApplicationAdapterHandlers/FileCommon/AwaitAutoResetEvent.cs similarity index 98% rename from SiMay.RemoteControlsCore/ApplicationAdapterHandler/FileCommon/AwaitAutoResetEvent.cs rename to SiMay.RemoteControlsCore/ApplicationAdapterHandlers/FileCommon/AwaitAutoResetEvent.cs index 186d78a..c83e112 100644 --- a/SiMay.RemoteControlsCore/ApplicationAdapterHandler/FileCommon/AwaitAutoResetEvent.cs +++ b/SiMay.RemoteControlsCore/ApplicationAdapterHandlers/FileCommon/AwaitAutoResetEvent.cs @@ -48,7 +48,7 @@ namespace SiMay.RemoteControlsCore.HandlerAdapters { LogHelper.DebugWriteLog(frame.GetMethod().Name + " AwaitOneData ----wait version:" + _version); _event.Reset(); - _event.WaitOne(1000); + _event.WaitOne(); LogHelper.DebugWriteLog(frame.GetMethod().Name + " AwaitOneData ----wait finish version:" + _version); } return this._buffer; diff --git a/SiMay.RemoteControlsCore/ApplicationAdapterHandler/KeyboardAdapterHandler.cs b/SiMay.RemoteControlsCore/ApplicationAdapterHandlers/KeyboardAdapterHandler.cs similarity index 100% rename from SiMay.RemoteControlsCore/ApplicationAdapterHandler/KeyboardAdapterHandler.cs rename to SiMay.RemoteControlsCore/ApplicationAdapterHandlers/KeyboardAdapterHandler.cs diff --git a/SiMay.RemoteControlsCore/ApplicationAdapterHandler/RegistryEditorAdapterHandler.cs b/SiMay.RemoteControlsCore/ApplicationAdapterHandlers/RegistryEditorAdapterHandler.cs similarity index 100% rename from SiMay.RemoteControlsCore/ApplicationAdapterHandler/RegistryEditorAdapterHandler.cs rename to SiMay.RemoteControlsCore/ApplicationAdapterHandlers/RegistryEditorAdapterHandler.cs diff --git a/SiMay.RemoteControlsCore/ApplicationAdapterHandler/RemoteFileAdapterHandler.cs b/SiMay.RemoteControlsCore/ApplicationAdapterHandlers/RemoteFileAdapterHandler.cs similarity index 97% rename from SiMay.RemoteControlsCore/ApplicationAdapterHandler/RemoteFileAdapterHandler.cs rename to SiMay.RemoteControlsCore/ApplicationAdapterHandlers/RemoteFileAdapterHandler.cs index 478a8cf..611cdaa 100644 --- a/SiMay.RemoteControlsCore/ApplicationAdapterHandler/RemoteFileAdapterHandler.cs +++ b/SiMay.RemoteControlsCore/ApplicationAdapterHandlers/RemoteFileAdapterHandler.cs @@ -382,8 +382,9 @@ namespace SiMay.RemoteControlsCore.HandlerAdapters [PacketHandler(MessageHead.C_FILE_FRIST_DATA)] private void SetOpenEvent(SessionProviderContext session) { - LogHelper.DebugWriteLog("C_FILE_FRIST_DATA SetOpenEvent head:" + string.Join(",", session.CompletedBuffer.Take(2).Select(c => c.ToString()).ToArray()) /*+ " fileName:" + session.CompletedBuffer.GetMessageEntity().fileName*/); - _workerStreamEvent.SetOneData(GetMessage(session)); + //LogHelper.DebugWriteLog("C_FILE_FRIST_DATA SetOpenEvent head:" + string.Join(",", session.CompletedBuffer.Take(2).Select(c => c.ToString()).ToArray()) /*+ " fileName:" + session.CompletedBuffer.GetMessageEntity().fileName*/); + var data = GetMessage(session); + _workerStreamEvent.SetOneData(data); } private async Task AwaitOpenDownloadData(string remoteFileName, long position) { @@ -401,7 +402,7 @@ namespace SiMay.RemoteControlsCore.HandlerAdapters var data = _workerStreamEvent.AwaitOneData(); if (data.IsNullOrEmpty()) return null; - LogHelper.DebugWriteLog("AwaitFristDownloadData head:" + string.Join(",", data.Take(2).Select(c => c.ToString()).ToArray()) + " buffer lenght:" + data.Length); + //LogHelper.DebugWriteLog("AwaitFristDownloadData head:" + string.Join(",", data.Take(2).Select(c => c.ToString()).ToArray()) + " buffer lenght:" + data.Length); return PacketSerializeHelper.DeserializePacket(data); } else @@ -412,8 +413,9 @@ namespace SiMay.RemoteControlsCore.HandlerAdapters [PacketHandler(MessageHead.C_FILE_DATA)] private void SetDataOneEvent(SessionProviderContext session) { - LogHelper.DebugWriteLog("SetDataOneEvent head:" + string.Join(",", session.CompletedBuffer.Take(2).Select(c => c.ToString()).ToArray())); - _workerStreamEvent.SetOneData(GetMessage(session)); + //LogHelper.DebugWriteLog("SetDataOneEvent head:" + string.Join(",", session.CompletedBuffer.Take(2).Select(c => c.ToString()).ToArray())); + var data = GetMessage(session); + _workerStreamEvent.SetOneData(); } private async Task AwaitDownloadDataPack() { diff --git a/SiMay.RemoteControlsCore/ApplicationAdapterHandler/RemoteScreenAdapterHandler.cs b/SiMay.RemoteControlsCore/ApplicationAdapterHandlers/RemoteScreenAdapterHandler.cs similarity index 100% rename from SiMay.RemoteControlsCore/ApplicationAdapterHandler/RemoteScreenAdapterHandler.cs rename to SiMay.RemoteControlsCore/ApplicationAdapterHandlers/RemoteScreenAdapterHandler.cs diff --git a/SiMay.RemoteControlsCore/ApplicationAdapterHandlers/RemoteUpdateAdapterHandler.cs b/SiMay.RemoteControlsCore/ApplicationAdapterHandlers/RemoteUpdateAdapterHandler.cs new file mode 100644 index 0000000..cdd09a4 --- /dev/null +++ b/SiMay.RemoteControlsCore/ApplicationAdapterHandlers/RemoteUpdateAdapterHandler.cs @@ -0,0 +1,36 @@ +using SiMay.Core; +using SiMay.Core.PacketModelBinder.Attributes; +using SiMay.Net.SessionProvider; +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace SiMay.RemoteControlsCore +{ + public class RemoteUpdateAdapterHandler : ApplicationAdapterHandler + { + /// + /// 远程更新就绪 + /// + public event Action OnRemoteUpdateReadyEventHandler; + + /// + /// 获取下一个数据 + /// + public event Action OnNextDataEventHandler; + + [PacketHandler(MessageHead.C_REMOTE_UPDATE_READY)] + public void ReadyHandler(SessionProviderContext session) + => OnRemoteUpdateReadyEventHandler?.Invoke(); + + + [PacketHandler(MessageHead.C_REMOTE_UPDATE_NEXT_DATA)] + public void NextDataHandler(SessionProviderContext session) + => OnNextDataEventHandler?.Invoke(); + + public void SendFileData(byte[] data) + => SendTo(CurrentSession, MessageHead.S_REMOTE_UPDATE_DATA, data); + } +} diff --git a/SiMay.RemoteControlsCore/ApplicationAdapterHandler/ShellAdapterHandler.cs b/SiMay.RemoteControlsCore/ApplicationAdapterHandlers/ShellAdapterHandler.cs similarity index 100% rename from SiMay.RemoteControlsCore/ApplicationAdapterHandler/ShellAdapterHandler.cs rename to SiMay.RemoteControlsCore/ApplicationAdapterHandlers/ShellAdapterHandler.cs diff --git a/SiMay.RemoteControlsCore/ApplicationAdapterHandler/StartupAdapterHandler.cs b/SiMay.RemoteControlsCore/ApplicationAdapterHandlers/StartupAdapterHandler.cs similarity index 100% rename from SiMay.RemoteControlsCore/ApplicationAdapterHandler/StartupAdapterHandler.cs rename to SiMay.RemoteControlsCore/ApplicationAdapterHandlers/StartupAdapterHandler.cs diff --git a/SiMay.RemoteControlsCore/ApplicationAdapterHandler/SystemAdapterHandler.cs b/SiMay.RemoteControlsCore/ApplicationAdapterHandlers/SystemAdapterHandler.cs similarity index 100% rename from SiMay.RemoteControlsCore/ApplicationAdapterHandler/SystemAdapterHandler.cs rename to SiMay.RemoteControlsCore/ApplicationAdapterHandlers/SystemAdapterHandler.cs diff --git a/SiMay.RemoteControlsCore/ApplicationAdapterHandler/TcpConnectionAdapterHandler.cs b/SiMay.RemoteControlsCore/ApplicationAdapterHandlers/TcpConnectionAdapterHandler.cs similarity index 100% rename from SiMay.RemoteControlsCore/ApplicationAdapterHandler/TcpConnectionAdapterHandler.cs rename to SiMay.RemoteControlsCore/ApplicationAdapterHandlers/TcpConnectionAdapterHandler.cs diff --git a/SiMay.RemoteControlsCore/ApplicationAdapterHandler/VideoAppAdapterHandler.cs b/SiMay.RemoteControlsCore/ApplicationAdapterHandlers/VideoAppAdapterHandler.cs similarity index 100% rename from SiMay.RemoteControlsCore/ApplicationAdapterHandler/VideoAppAdapterHandler.cs rename to SiMay.RemoteControlsCore/ApplicationAdapterHandlers/VideoAppAdapterHandler.cs diff --git a/SiMay.RemoteControlsCore/Interface/IApplication.cs b/SiMay.RemoteControlsCore/Interface/IApplication.cs index e44ca41..8601625 100644 --- a/SiMay.RemoteControlsCore/Interface/IApplication.cs +++ b/SiMay.RemoteControlsCore/Interface/IApplication.cs @@ -15,6 +15,12 @@ namespace SiMay.RemoteControlsCore /// void Start(); + /// + /// 设置参数 + /// + /// + void SetParameter(object arg); + /// /// 当会话断开时 /// diff --git a/SiMay.RemoteControlsCore/MainApplicationAdapterHandler.cs b/SiMay.RemoteControlsCore/MainApplicationAdapterHandler.cs index 719a12b..d2db9d4 100644 --- a/SiMay.RemoteControlsCore/MainApplicationAdapterHandler.cs +++ b/SiMay.RemoteControlsCore/MainApplicationAdapterHandler.cs @@ -57,6 +57,12 @@ namespace SiMay.RemoteControlsCore /// public event Action OnProxyNotifyHandlerEvent; + /// + /// 当应用被创建 + /// + public event Action OnApplicationCreatedEventHandler; + + /// /// 监听日志事件 /// @@ -425,6 +431,8 @@ namespace SiMay.RemoteControlsCore .Single(c => !c.GetCustomAttribute(true).IsNull()); handlerFieder.SetValue(app, appHandlerBase); + this.OnApplicationCreatedEventHandler?.Invoke(app); + //app.HandlerAdapter = handlerBase; app.Start(); diff --git a/SiMay.RemoteControlsCore/SiMay.RemoteControlsCore.csproj b/SiMay.RemoteControlsCore/SiMay.RemoteControlsCore.csproj index cb9abca..ed55fed 100644 --- a/SiMay.RemoteControlsCore/SiMay.RemoteControlsCore.csproj +++ b/SiMay.RemoteControlsCore/SiMay.RemoteControlsCore.csproj @@ -49,6 +49,7 @@ + @@ -64,17 +65,17 @@ - - - - - - - - - - - + + + + + + + + + + + diff --git a/SiMay.RemoteMonitor/Application/AudioApplication.Designer.cs b/SiMay.RemoteMonitor/Application/AudioApplication.Designer.cs index f5cad09..ea4af58 100644 --- a/SiMay.RemoteMonitor/Application/AudioApplication.Designer.cs +++ b/SiMay.RemoteMonitor/Application/AudioApplication.Designer.cs @@ -54,18 +54,21 @@ this.groupBox1.Controls.Add(this.recvdataLen); this.groupBox1.Controls.Add(this.label2); this.groupBox1.Controls.Add(this.tip); - this.groupBox1.Location = new System.Drawing.Point(7, 1); + this.groupBox1.Location = new System.Drawing.Point(9, 1); + this.groupBox1.Margin = new System.Windows.Forms.Padding(4, 4, 4, 4); this.groupBox1.Name = "groupBox1"; - this.groupBox1.Size = new System.Drawing.Size(519, 142); + this.groupBox1.Padding = new System.Windows.Forms.Padding(4, 4, 4, 4); + this.groupBox1.Size = new System.Drawing.Size(692, 178); this.groupBox1.TabIndex = 0; this.groupBox1.TabStop = false; // // checkBox2 // this.checkBox2.AutoSize = true; - this.checkBox2.Location = new System.Drawing.Point(157, 107); + this.checkBox2.Location = new System.Drawing.Point(209, 134); + this.checkBox2.Margin = new System.Windows.Forms.Padding(4, 4, 4, 4); this.checkBox2.Name = "checkBox2"; - this.checkBox2.Size = new System.Drawing.Size(96, 16); + this.checkBox2.Size = new System.Drawing.Size(119, 19); this.checkBox2.TabIndex = 11; this.checkBox2.Text = "录制远程声音"; this.checkBox2.UseVisualStyleBackColor = true; @@ -74,17 +77,19 @@ // labRuntime // this.labRuntime.AutoSize = true; - this.labRuntime.Location = new System.Drawing.Point(304, 108); + this.labRuntime.Location = new System.Drawing.Point(405, 135); + this.labRuntime.Margin = new System.Windows.Forms.Padding(4, 0, 4, 0); this.labRuntime.Name = "labRuntime"; - this.labRuntime.Size = new System.Drawing.Size(113, 12); + this.labRuntime.Size = new System.Drawing.Size(148, 15); this.labRuntime.TabIndex = 10; this.labRuntime.Text = "已运行:00.00.00.00"; // // button1 // - this.button1.Location = new System.Drawing.Point(423, 103); + this.button1.Location = new System.Drawing.Point(564, 129); + this.button1.Margin = new System.Windows.Forms.Padding(4, 4, 4, 4); this.button1.Name = "button1"; - this.button1.Size = new System.Drawing.Size(75, 23); + this.button1.Size = new System.Drawing.Size(100, 29); this.button1.TabIndex = 9; this.button1.Text = "设置"; this.button1.UseVisualStyleBackColor = true; @@ -92,36 +97,40 @@ // // progressBar1 // - this.progressBar1.Location = new System.Drawing.Point(200, 55); + this.progressBar1.Location = new System.Drawing.Point(370, 69); + this.progressBar1.Margin = new System.Windows.Forms.Padding(4, 4, 4, 4); this.progressBar1.Name = "progressBar1"; - this.progressBar1.Size = new System.Drawing.Size(298, 9); + this.progressBar1.Size = new System.Drawing.Size(294, 11); this.progressBar1.Style = System.Windows.Forms.ProgressBarStyle.Marquee; this.progressBar1.TabIndex = 7; // // sendataLen // this.sendataLen.AutoSize = true; - this.sendataLen.Location = new System.Drawing.Point(70, 75); + this.sendataLen.Location = new System.Drawing.Point(93, 94); + this.sendataLen.Margin = new System.Windows.Forms.Padding(4, 0, 4, 0); this.sendataLen.Name = "sendataLen"; - this.sendataLen.Size = new System.Drawing.Size(29, 12); + this.sendataLen.Size = new System.Drawing.Size(39, 15); this.sendataLen.TabIndex = 6; this.sendataLen.Text = "0 KB"; // // label3 // this.label3.AutoSize = true; - this.label3.Location = new System.Drawing.Point(17, 75); + this.label3.Location = new System.Drawing.Point(23, 94); + this.label3.Margin = new System.Windows.Forms.Padding(4, 0, 4, 0); this.label3.Name = "label3"; - this.label3.Size = new System.Drawing.Size(47, 12); + this.label3.Size = new System.Drawing.Size(60, 15); this.label3.TabIndex = 5; this.label3.Text = "已发送:"; // // checkBox1 // this.checkBox1.AutoSize = true; - this.checkBox1.Location = new System.Drawing.Point(19, 107); + this.checkBox1.Location = new System.Drawing.Point(25, 134); + this.checkBox1.Margin = new System.Windows.Forms.Padding(4, 4, 4, 4); this.checkBox1.Name = "checkBox1"; - this.checkBox1.Size = new System.Drawing.Size(132, 16); + this.checkBox1.Size = new System.Drawing.Size(164, 19); this.checkBox1.TabIndex = 3; this.checkBox1.Text = "发送本地语音到远程"; this.checkBox1.UseVisualStyleBackColor = true; @@ -130,18 +139,20 @@ // recvdataLen // this.recvdataLen.AutoSize = true; - this.recvdataLen.Location = new System.Drawing.Point(70, 55); + this.recvdataLen.Location = new System.Drawing.Point(93, 69); + this.recvdataLen.Margin = new System.Windows.Forms.Padding(4, 0, 4, 0); this.recvdataLen.Name = "recvdataLen"; - this.recvdataLen.Size = new System.Drawing.Size(29, 12); + this.recvdataLen.Size = new System.Drawing.Size(39, 15); this.recvdataLen.TabIndex = 2; this.recvdataLen.Text = "0 KB"; // // label2 // this.label2.AutoSize = true; - this.label2.Location = new System.Drawing.Point(17, 55); + this.label2.Location = new System.Drawing.Point(23, 69); + this.label2.Margin = new System.Windows.Forms.Padding(4, 0, 4, 0); this.label2.Name = "label2"; - this.label2.Size = new System.Drawing.Size(47, 12); + this.label2.Size = new System.Drawing.Size(60, 15); this.label2.TabIndex = 1; this.label2.Text = "已接收:"; // @@ -149,19 +160,21 @@ // this.tip.AutoSize = true; this.tip.ForeColor = System.Drawing.Color.Red; - this.tip.Location = new System.Drawing.Point(17, 32); + this.tip.Location = new System.Drawing.Point(23, 40); + this.tip.Margin = new System.Windows.Forms.Padding(4, 0, 4, 0); this.tip.Name = "tip"; - this.tip.Size = new System.Drawing.Size(137, 12); + this.tip.Size = new System.Drawing.Size(175, 15); this.tip.TabIndex = 0; this.tip.Text = "正在监听远程声音......"; // // AudioApplication // - this.AutoScaleDimensions = new System.Drawing.SizeF(6F, 12F); + this.AutoScaleDimensions = new System.Drawing.SizeF(8F, 15F); this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font; - this.ClientSize = new System.Drawing.Size(533, 151); + this.ClientSize = new System.Drawing.Size(711, 189); this.Controls.Add(this.groupBox1); this.FormBorderStyle = System.Windows.Forms.FormBorderStyle.FixedSingle; + this.Margin = new System.Windows.Forms.Padding(4, 4, 4, 4); this.MaximizeBox = false; this.Name = "AudioApplication"; this.StartPosition = System.Windows.Forms.FormStartPosition.CenterScreen; diff --git a/SiMay.RemoteMonitor/Application/AudioApplication.cs b/SiMay.RemoteMonitor/Application/AudioApplication.cs index 5d3b3e8..6f86f59 100644 --- a/SiMay.RemoteMonitor/Application/AudioApplication.cs +++ b/SiMay.RemoteMonitor/Application/AudioApplication.cs @@ -24,16 +24,21 @@ namespace SiMay.RemoteMonitor.Application private WinSoundRecord _recorder; private WinSoundPlayer _player; - private FileStream _fileStream; + private bool _isRun = false; private bool _isPlaying = true; private int _recvVoiceDataLength = 0; private int _sendVoiceDataLength = 0; private int _soundBufferCount = 8; + private int _samplesPerSecond; + private short _bitsPerSample; + private short _channels; + private int _dataBufferSize; + private bool _isRecord = false; private DateTime _runtimeSpan; - + private PCMStreamToWavHelper _pcmStreamToWavHelper; public AudioApplication() { InitializeComponent(); @@ -44,6 +49,11 @@ namespace SiMay.RemoteMonitor.Application this.Show(); } + public void SetParameter(object arg) + { + throw new NotImplementedException(); + } + public void SessionClose(ApplicationAdapterHandler handler) { this.Text = this._title + " [" + this.AudioAdapterHandler.StateContext.ToString() + "]"; @@ -61,7 +71,7 @@ namespace SiMay.RemoteMonitor.Application this.AudioAdapterHandler.OnOpenDeviceStatusEventHandler += OnOpenDeviceStatusEventHandler; this.AudioAdapterHandler.OnPlayerEventHandler += OnPlayerEventHandler; Initialize(); - + this._runtimeSpan = DateTime.Now; System.Timers.Timer timer = new System.Timers.Timer(); timer.Interval = 1000; @@ -79,10 +89,10 @@ namespace SiMay.RemoteMonitor.Application }; timer.Start(); - + } - private async void OnPlayerEventHandler(AudioAdapterHandler adapterHandler, byte[] voiceData) + private void OnPlayerEventHandler(AudioAdapterHandler adapterHandler, byte[] voiceData) { if (this._isRun && this._player != null && this._isPlaying == true) { @@ -95,7 +105,7 @@ namespace SiMay.RemoteMonitor.Application })); this._player.PlayData(voiceData); if (this._isRecord) - await this._fileStream.WriteAsync(voiceData, 0, voiceData.Length); + this._pcmStreamToWavHelper.WritePCMDataChunk(voiceData); } catch { } } @@ -115,16 +125,17 @@ namespace SiMay.RemoteMonitor.Application private void Initialize() { - int samplesPerSecond = AppConfiguration.AudioSamplesPerSecond; - int bitsPerSample = AppConfiguration.AudioBitsPerSample; - int channels = AppConfiguration.AudioChannels; + _samplesPerSecond = AppConfiguration.AudioSamplesPerSecond; + _bitsPerSample = (short)AppConfiguration.AudioBitsPerSample; + _channels = (short)AppConfiguration.AudioChannels; + _dataBufferSize = 1280; string waveOutDeviceName = WinSound.GetWaveOutDeviceNames().Count > 0 ? WinSound.GetWaveOutDeviceNames()[0] : null; if (waveOutDeviceName != null) { _player = new WinSoundPlayer(); - _player.Open(waveOutDeviceName, samplesPerSecond, bitsPerSample, channels, 1280, _soundBufferCount); + _player.Open(waveOutDeviceName, _samplesPerSecond, _bitsPerSample, _channels, _dataBufferSize, _soundBufferCount); } else { @@ -137,13 +148,13 @@ namespace SiMay.RemoteMonitor.Application { _recorder = new WinSoundRecord(); _recorder.DataRecorded += Recorder_DataRecorded; - _recorder.Open(waveInDeviceName, samplesPerSecond, bitsPerSample, channels, 1280, _soundBufferCount); + _recorder.Open(waveInDeviceName, _samplesPerSecond, _bitsPerSample, _channels, _dataBufferSize, _soundBufferCount); } else { MessageBoxHelper.ShowBoxExclamation("本机未找到录音设备!"); } - this.AudioAdapterHandler.StartRemoteAudio(samplesPerSecond, bitsPerSample, channels); + this.AudioAdapterHandler.StartRemoteAudio(_samplesPerSecond, _bitsPerSample, _channels); this._isRun = true; } @@ -204,16 +215,22 @@ namespace SiMay.RemoteMonitor.Application private void checkBox2_CheckedChanged(object sender, EventArgs e) { - this._isRecord = checkBox2.Checked; if (checkBox2.Checked) - _fileStream = new FileStream(DateTime.Now.ToFileTime() + ".PCM", FileMode.CreateNew, FileAccess.ReadWrite, FileShare.ReadWrite); + { + var directory = Path.Combine(Environment.CurrentDirectory, AudioAdapterHandler.OriginName); + if (!Directory.Exists(directory)) + Directory.CreateDirectory(directory); + + var fileName = Path.Combine(directory, $"语音_{DateTime.Now.ToString("yyyy-MM-dd hh_mm_ss")}.wav"); + + _pcmStreamToWavHelper = new PCMStreamToWavHelper(fileName, _samplesPerSecond, _bitsPerSample, _channels, _dataBufferSize); + } else { - string name = _fileStream.Name; - _fileStream.Flush(); - _fileStream.Close(); - MessageBoxHelper.ShowBoxExclamation("录音已完成,文件位于:" + name); + _pcmStreamToWavHelper.Close(); + MessageBoxHelper.ShowBoxExclamation($"录音已完成,文件位于:{_pcmStreamToWavHelper.FileName}"); } + this._isRecord = checkBox2.Checked; } } } \ No newline at end of file diff --git a/SiMay.RemoteMonitor/Application/FileApplication.cs b/SiMay.RemoteMonitor/Application/FileApplication.cs index 97239b5..407af22 100644 --- a/SiMay.RemoteMonitor/Application/FileApplication.cs +++ b/SiMay.RemoteMonitor/Application/FileApplication.cs @@ -61,6 +61,11 @@ namespace SiMay.RemoteMonitor.Application this.Show(); } + public void SetParameter(object arg) + { + throw new NotImplementedException(); + } + public void SessionClose(ApplicationAdapterHandler handler) { this.Text = this._title + " [" + this.RemoteFileAdapterHandler.StateContext.ToString() + "]"; diff --git a/SiMay.RemoteMonitor/Application/KeyboardApplication.cs b/SiMay.RemoteMonitor/Application/KeyboardApplication.cs index 8dc31b7..e64d7a7 100644 --- a/SiMay.RemoteMonitor/Application/KeyboardApplication.cs +++ b/SiMay.RemoteMonitor/Application/KeyboardApplication.cs @@ -37,6 +37,11 @@ namespace SiMay.RemoteMonitor.Application this.Show(); } + public void SetParameter(object arg) + { + throw new NotImplementedException(); + } + public void SessionClose(ApplicationAdapterHandler handler) { this.Text = _title + " [" + this.KeyboardAdapterHandler.StateContext.ToString() + "]"; diff --git a/SiMay.RemoteMonitor/Application/RegEditorApplication.cs b/SiMay.RemoteMonitor/Application/RegEditorApplication.cs index 9b78e4a..eb07beb 100644 --- a/SiMay.RemoteMonitor/Application/RegEditorApplication.cs +++ b/SiMay.RemoteMonitor/Application/RegEditorApplication.cs @@ -44,6 +44,11 @@ namespace SiMay.RemoteMonitor.Application this.Show(); } + public void SetParameter(object arg) + { + throw new NotImplementedException(); + } + public void SessionClose(ApplicationAdapterHandler handler) { this.Text = this._title + " [" + this.RegistryEditorAdapterHandler.StateContext.ToString() + "]"; diff --git a/SiMay.RemoteMonitor/Application/ScreenApplication.cs b/SiMay.RemoteMonitor/Application/ScreenApplication.cs index 11ee7f9..6cebe01 100644 --- a/SiMay.RemoteMonitor/Application/ScreenApplication.cs +++ b/SiMay.RemoteMonitor/Application/ScreenApplication.cs @@ -13,6 +13,11 @@ using SiMay.RemoteMonitor.MainApplication; using SiMay.RemoteControlsCore.HandlerAdapters; using static SiMay.RemoteMonitor.Win32Api; using static SiMay.Serialize.Standard.PacketSerializeHelper; +using System.Diagnostics; +using Accord.Video.FFMPEG; +using System.Threading; +using System.Threading.Tasks; +using SiMay.Core.ScreenSpy.Entitys; namespace SiMay.RemoteMonitor.Application { @@ -39,6 +44,7 @@ namespace SiMay.RemoteMonitor.Application private const Int32 IDM_CTRL_ALT_DEL = 1014; private const Int32 IDM_DELETE_WALLPAPER = 1015; private const Int32 IDM_CHANGE_MONITOR = 1016; + private const Int32 IDM_RECORD = 1017; [ApplicationAdapterHandler] public RemoteScreenAdapterHandler RemoteScreenAdapterHandler { get; set; } @@ -57,9 +63,14 @@ namespace SiMay.RemoteMonitor.Application private int _currenMonitorIndex = 0; private MonitorItem[] _monitorItems; - private Bitmap _image; - private Timer _timer; + private Graphics _currentFrameGraphics; + private Graphics _videoFrameGraphics; + private Bitmap _currentFrame; + private Bitmap _videoFrame; + private System.Windows.Forms.Timer _timer; + private bool _stop = true; + private int _menuContextIndex; public ScreenApplication() { InitializeComponent(); @@ -69,6 +80,12 @@ namespace SiMay.RemoteMonitor.Application this.Show(); } + public void SetParameter(object arg) + { + throw new NotImplementedException(); + } + + public void SessionClose(ApplicationAdapterHandler handler) { _timer.Stop(); @@ -109,11 +126,14 @@ namespace SiMay.RemoteMonitor.Application InsertMenu(sysMenuHandle, index++, MF_BYPOSITION, IDM_CHANGE_MONITOR, "监视器设置"); InsertMenu(sysMenuHandle, index++, MF_BYPOSITION, IDM_CTRL_ALT_DEL, "Ctrl + Alt + Del"); + _menuContextIndex = index++; + InsertMenu(sysMenuHandle, _menuContextIndex, MF_BYPOSITION, IDM_RECORD, "开始录制"); + CheckMenuItem(sysMenuHandle, IDM_FULL_SCREEN, MF_CHECKED); CheckMenuItem(sysMenuHandle, IDM_FULL_DIFFER, MF_CHECKED); CheckMenuItem(sysMenuHandle, IDM_16X, MF_CHECKED); - _timer = new Timer(); + _timer = new System.Windows.Forms.Timer(); _timer.Interval = 1000; _timer.Tick += Timer_Tick; _timer.Start(); @@ -125,87 +145,6 @@ namespace SiMay.RemoteMonitor.Application this.RemoteScreenAdapterHandler.GetInitializeBitInfo(); } - private void OnServcieInitEventHandler(RemoteScreenAdapterHandler adapterHandler, int height, int width, int currentMonitorIndex, MonitorItem[] monitorItems) - { - this._currenMonitorIndex = currentMonitorIndex; - this._monitorItems = monitorItems; - this._srcImageWidth = width; - this._srcImageHeight = height; - _image = new Bitmap(width, height); - Graphics g = Graphics.FromImage(_image); - g.Clear(Color.Black); - g.DrawString("桌面加载中...", new Font("微软雅黑", 15, FontStyle.Regular), new SolidBrush(Color.Red), new Point((height / 2) - 40, width / 2)); - g.Dispose(); - this.StartGetScreen(); - } - - private void OnScreenFragmentEventHandler(RemoteScreenAdapterHandler adapterHandler, Core.ScreenSpy.Entitys.Fragment[] fragments, ScreenReceivedType type) - { - switch (type) - { - case ScreenReceivedType.Noninterlaced: - foreach (var fragment in fragments) - { - using (MemoryStream ms = new MemoryStream(fragment.FragmentData)) - { - this.DisplayScreen(Image.FromStream(ms), new Rectangle(fragment.X, fragment.Y, fragment.Width, fragment.Height)); - _traffic += ms.Length; - } - } - _recvImgCount++; - this.GetNextScreen(); - break; - case ScreenReceivedType.Difference: - - foreach (var fragment in fragments) - { - using (MemoryStream ms = new MemoryStream(fragment.FragmentData)) - { - this.DisplayScreen(Image.FromStream(ms), new Rectangle(fragment.X, fragment.Y, fragment.Width, fragment.Height)); - _traffic += ms.Length; - } - } - break; - case ScreenReceivedType.DifferenceEnd: - _recvImgCount++; - this.GetNextScreen(); - break; - default: - break; - } - } - - private void StartGetScreen() - { - if (_screenDisplayMode == ScreenDisplayMode.Fullscreen) - this.RemoteScreenAdapterHandler.StartGetScreen(this._image.Height, this._image.Width, Math.Abs(this.imgDesktop.Left), Math.Abs(this.imgDesktop.Top), this._screenDisplayMode); - else - this.RemoteScreenAdapterHandler.StartGetScreen(this.ClientSize.Height, this.ClientSize.Width, Math.Abs(this.imgDesktop.Left), Math.Abs(this.imgDesktop.Top), this._screenDisplayMode); - } - - private void GetNextScreen() - { - if (_screenDisplayMode == ScreenDisplayMode.Fullscreen) - this.RemoteScreenAdapterHandler.GetNextScreen(this._image.Height, this._image.Width, Math.Abs(this.imgDesktop.Left), Math.Abs(this.imgDesktop.Top), this._screenDisplayMode); - else - this.RemoteScreenAdapterHandler.GetNextScreen(this.ClientSize.Height, this.ClientSize.Width, Math.Abs(this.imgDesktop.Left), Math.Abs(this.imgDesktop.Top), this._screenDisplayMode); - } - - private void OnClipoardReceivedEventHandler(RemoteScreenAdapterHandler adapterHandler, string text) - { - Clipboard.SetText(text); - MessageBoxHelper.ShowBoxExclamation("已获取剪切板内容!"); - } - - private void Timer_Tick(object sender, EventArgs e) - { - if (_continueTask) - { - this.Text = string.Format(_title, _recvImgCount.ToString(), (_traffic / (float)1024).ToString("0.00")); - _recvImgCount = 0; - } - } - protected override void WndProc(ref Message m) { if (m.Msg == WM_SYSCOMMAND) @@ -348,21 +287,156 @@ namespace SiMay.RemoteMonitor.Application case IDM_DELETE_WALLPAPER: this.RemoteScreenAdapterHandler.RemoteDeleteWallPaper(); break; + case IDM_RECORD: + if (_stop) + { + if (_srcImageHeight == 0 || _srcImageWidth == 0) + return; + if (!_videoFrameGraphics.IsNull()) + _videoFrameGraphics.Dispose(); + if (!_videoFrame.IsNull()) + _videoFrame.Dispose(); + lock (this) + { + _videoFrame = new Bitmap(this._srcImageWidth, this._srcImageHeight); + _videoFrameGraphics = Graphics.FromImage(_videoFrame); + _videoFrameGraphics.DrawImage(_currentFrame, 0, 0); + } + _stop = false; + ModifyMenu(sysMenuHandle, _menuContextIndex, MF_BYPOSITION, IDM_RECORD, "停止录制"); + Task.Run(CreateDesktopRecordThread); + } + else + { + _stop = true; + ModifyMenu(sysMenuHandle, _menuContextIndex, MF_BYPOSITION, IDM_RECORD, "开始录制"); + } + break; } } base.WndProc(ref m); } - private void DisplayScreen(Image bit, Rectangle rect) + private void OnServcieInitEventHandler(RemoteScreenAdapterHandler adapterHandler, int height, int width, int currentMonitorIndex, MonitorItem[] monitorItems) + { + if (!_videoFrameGraphics.IsNull()) + _videoFrameGraphics.Dispose(); + + this._currenMonitorIndex = currentMonitorIndex; + this._monitorItems = monitorItems; + this._srcImageWidth = width; + this._srcImageHeight = height; + + _currentFrame = new Bitmap(width, height); + _currentFrameGraphics = Graphics.FromImage(_currentFrame); + + Graphics g = Graphics.FromImage(_currentFrame); + g.Clear(Color.Black); + g.DrawString("桌面加载中...", new Font("微软雅黑", 15, FontStyle.Regular), new SolidBrush(Color.Red), new Point((height / 2) - 40, width / 2)); + g.Dispose(); + this.StartGetScreen(); + } + + private void OnScreenFragmentEventHandler(RemoteScreenAdapterHandler adapterHandler, Fragment[] fragments, ScreenReceivedType type) + { + switch (type) + { + case ScreenReceivedType.Noninterlaced: + this.FrameDataHandler(fragments); + _recvImgCount++; + this.GetNextScreen(); + break; + case ScreenReceivedType.Difference: + this.FrameDataHandler(fragments); + break; + case ScreenReceivedType.DifferenceEnd: + _recvImgCount++; + this.GetNextScreen(); + break; + default: + break; + } + this.imgDesktop.Image = this._currentFrame; + } + + private void FrameDataHandler(Fragment[] fragments) { if (this.RemoteScreenAdapterHandler.WhetherClose) return; + lock (this) + { + foreach (var fragment in fragments) + { + using (MemoryStream ms = new MemoryStream(fragment.FragmentData)) + { + var rect = new Rectangle(fragment.X, fragment.Y, fragment.Width, fragment.Height); + var childFrame = Image.FromStream(ms); - Graphics g = Graphics.FromImage(_image); - g.DrawImage(bit, rect); - g.Dispose(); - bit.Dispose(); - imgDesktop.Image = _image; + this._currentFrameGraphics.DrawImage(childFrame, rect); + + if (!_stop) + this._videoFrameGraphics.DrawImage(childFrame, rect); + + childFrame.Dispose(); + _traffic += ms.Length; + } + } + } + } + + private void StartGetScreen() + { + //if (_screenDisplayMode == ScreenDisplayMode.Fullscreen) + this.RemoteScreenAdapterHandler.StartGetScreen(this._srcImageHeight, this._srcImageWidth, Math.Abs(this.imgDesktop.Left), Math.Abs(this.imgDesktop.Top), ScreenDisplayMode.Original); + //else + // this.RemoteScreenAdapterHandler.StartGetScreen(this.ClientSize.Height, this.ClientSize.Width, Math.Abs(this.imgDesktop.Left), Math.Abs(this.imgDesktop.Top), this._screenDisplayMode); + } + + private void GetNextScreen() + { + //if (_screenDisplayMode == ScreenDisplayMode.Fullscreen) + this.RemoteScreenAdapterHandler.GetNextScreen(this._srcImageHeight, this._srcImageWidth, Math.Abs(this.imgDesktop.Left), Math.Abs(this.imgDesktop.Top), ScreenDisplayMode.Original); + //else + // this.RemoteScreenAdapterHandler.GetNextScreen(this.ClientSize.Height, this.ClientSize.Width, Math.Abs(this.imgDesktop.Left), Math.Abs(this.imgDesktop.Top), this._screenDisplayMode); + } + + private void OnClipoardReceivedEventHandler(RemoteScreenAdapterHandler adapterHandler, string text) + { + Clipboard.SetText(text); + MessageBoxHelper.ShowBoxExclamation("已获取剪切板内容!"); + } + + private void Timer_Tick(object sender, EventArgs e) + { + if (_continueTask) + { + this.Text = string.Format(_title, _recvImgCount.ToString(), (_traffic / (float)1024).ToString("0.00")); + _recvImgCount = 0; + } + } + + private async void CreateDesktopRecordThread() + { + var targetDirectory = Path.Combine(Environment.CurrentDirectory, RemoteScreenAdapterHandler.OriginName); + if (!Directory.Exists(targetDirectory)) + Directory.CreateDirectory(targetDirectory); + + var fileName = Path.Combine(targetDirectory, $"远程桌面_{RemoteScreenAdapterHandler.OriginName}_{DateTime.Now.ToString("yyyy-MM-dd hhmmss")}.avi"); + + var videoWriter = new VideoFileWriter(); + videoWriter.Open(fileName, _srcImageWidth, _srcImageHeight, 10, VideoCodec.H264); + + while (!_stop) + { + if (_videoFrame.IsNull()) + continue; + + lock (this) + videoWriter.WriteVideoFrame(_videoFrame); + GC.Collect(); + await Task.Delay(100); //帧率控制,每秒10帧,防止写入过快 + } + videoWriter.Close(); } private void ScreenSpyForm_KeyDown(object sender, KeyEventArgs e) @@ -455,6 +529,7 @@ namespace SiMay.RemoteMonitor.Application private void ScreenSpyForm_FormClosing(object sender, FormClosingEventArgs e) { + _stop = true; _timer.Stop(); _timer.Dispose(); this.RemoteScreenAdapterHandler.OnClipoardReceivedEventHandler -= OnClipoardReceivedEventHandler; diff --git a/SiMay.RemoteMonitor/Application/ShellApplication.cs b/SiMay.RemoteMonitor/Application/ShellApplication.cs index 3d8f6a9..0e35993 100644 --- a/SiMay.RemoteMonitor/Application/ShellApplication.cs +++ b/SiMay.RemoteMonitor/Application/ShellApplication.cs @@ -31,6 +31,11 @@ namespace SiMay.RemoteMonitor.Application this.Show(); } + public void SetParameter(object arg) + { + throw new NotImplementedException(); + } + public void SessionClose(ApplicationAdapterHandler handler) { this.Text = _title + " [" + this.ShellAdapterHandler.StateContext.ToString() + "]"; diff --git a/SiMay.RemoteMonitor/Application/StartupApplication.cs b/SiMay.RemoteMonitor/Application/StartupApplication.cs index 3ba8d3a..da6b1cb 100644 --- a/SiMay.RemoteMonitor/Application/StartupApplication.cs +++ b/SiMay.RemoteMonitor/Application/StartupApplication.cs @@ -36,6 +36,11 @@ namespace SiMay.RemoteMonitor.Application this.Show(); } + public void SetParameter(object arg) + { + throw new NotImplementedException(); + } + public void SessionClose(ApplicationAdapterHandler handler) { this.Text = _title + " [" + this.StartupAdapterHandler.StateContext.ToString() + "]"; diff --git a/SiMay.RemoteMonitor/Application/SystemApplication.cs b/SiMay.RemoteMonitor/Application/SystemApplication.cs index 0b4ff6e..86810d1 100644 --- a/SiMay.RemoteMonitor/Application/SystemApplication.cs +++ b/SiMay.RemoteMonitor/Application/SystemApplication.cs @@ -35,6 +35,11 @@ namespace SiMay.RemoteMonitor.Application this.Show(); } + public void SetParameter(object arg) + { + throw new NotImplementedException(); + } + public void SessionClose(ApplicationAdapterHandler handler) { this.Text = _title + " [" + this.SystemAdapterHandler.StateContext.ToString() + "]"; diff --git a/SiMay.RemoteMonitor/Application/TcpConnectionApplication.cs b/SiMay.RemoteMonitor/Application/TcpConnectionApplication.cs index f7eee0a..48316e6 100644 --- a/SiMay.RemoteMonitor/Application/TcpConnectionApplication.cs +++ b/SiMay.RemoteMonitor/Application/TcpConnectionApplication.cs @@ -31,6 +31,11 @@ namespace SiMay.RemoteMonitor.Application public void Start() => this.Show(); + public void SetParameter(object arg) + { + throw new NotImplementedException(); + } + public void SessionClose(ApplicationAdapterHandler handler) => this.Text = _title + " [" + handler.StateContext.ToString() + "]"; diff --git a/SiMay.RemoteMonitor/Application/VideoApplication.cs b/SiMay.RemoteMonitor/Application/VideoApplication.cs index e012073..2d9d999 100644 --- a/SiMay.RemoteMonitor/Application/VideoApplication.cs +++ b/SiMay.RemoteMonitor/Application/VideoApplication.cs @@ -1,13 +1,17 @@ -using SiMay.Basic; +using Accord.Video.FFMPEG; +using SiMay.Basic; using SiMay.Core; using SiMay.RemoteControlsCore; using SiMay.RemoteControlsCore.HandlerAdapters; using SiMay.RemoteMonitor.Attributes; using System; using System.Drawing; +using System.Drawing.Imaging; using System.IO; using System.Net; using System.Runtime.InteropServices; +using System.Threading; +using System.Threading.Tasks; using System.Windows.Forms; using static SiMay.RemoteMonitor.Win32Api; @@ -33,6 +37,12 @@ namespace SiMay.RemoteMonitor.Application => this.Show(); + public void SetParameter(object arg) + { + throw new NotImplementedException(); + } + + public void SessionClose(ApplicationAdapterHandler handler) => this.Text = _title + " [" + VideoAppAdapterHandler.StateContext.ToString() + "]"; @@ -47,20 +57,27 @@ namespace SiMay.RemoteMonitor.Application const Int32 IDM_DEFAULT = 1001; const Int32 IDM_LOW = 1002; const Int32 IDM_SAVE = 1003; + const Int32 IDM_RECORD = 1004; + private int _videoFrameWidth = 0; + private int _videoFrameHeight = 0; + private Bitmap _videoFrame; + private bool _stop = true; + private int _menuContextIndex = 0; private void VedioManager_Load(object sender, EventArgs e) { int index = 7; IntPtr sysMenuHandle = GetSystemMenu(this.Handle, false); - InsertMenu(sysMenuHandle, index, MF_SEPARATOR, 0, null); + InsertMenu(sysMenuHandle, index++, MF_SEPARATOR, 0, null); InsertMenu(sysMenuHandle, index++, MF_BYPOSITION, IDM_HEIGHT, "高画质"); InsertMenu(sysMenuHandle, index++, MF_BYPOSITION, IDM_DEFAULT, "中画质"); InsertMenu(sysMenuHandle, index++, MF_BYPOSITION, IDM_LOW, "低画质"); InsertMenu(sysMenuHandle, index++, MF_SEPARATOR, 0, null); InsertMenu(sysMenuHandle, index++, MF_BYPOSITION, IDM_SAVE, "保存快照"); + _menuContextIndex = index++; + InsertMenu(sysMenuHandle, _menuContextIndex, MF_BYPOSITION, IDM_RECORD, "开始录制"); CheckMenuItem(sysMenuHandle, IDM_DEFAULT, MF_CHECKED); - this.Text = _title = _title.Replace("#Name#", VideoAppAdapterHandler.OriginName); this.ShowTip("视频帧加载中..."); @@ -76,6 +93,19 @@ namespace SiMay.RemoteMonitor.Application private void OnImageFrameHandlerEvent(VideoAppAdapterHandler adapterHandler, Image image) { + lock (this) + { + _videoFrameHeight = image.Height; + _videoFrameWidth = image.Width; + + if (!_videoFrame.IsNull()) + _videoFrame.Dispose(); + + _videoFrame = new Bitmap(image.Width, image.Height); + Graphics g = Graphics.FromImage(_videoFrame); + g.DrawImage(image, 0, 0); + g.Dispose(); + } this.pictureBox.Image = image; } @@ -120,12 +150,51 @@ namespace SiMay.RemoteMonitor.Application img.Dispose(); MessageBoxHelper.ShowBoxExclamation("快照已保存到:" + fileName); + break; + case IDM_RECORD: + if (_stop) + { + if (_videoFrameWidth == 0 || _videoFrameHeight == 0) + return; + _stop = false; + ModifyMenu(sysMenuHandle, _menuContextIndex, MF_BYPOSITION, IDM_RECORD, "停止录制"); + Task.Run(CreateDesktopRecordThread); + } + else + { + _stop = true; + ModifyMenu(sysMenuHandle, _menuContextIndex, MF_BYPOSITION, IDM_RECORD, "开始录制"); + } break; } } base.WndProc(ref m); } + private async void CreateDesktopRecordThread() + { + var targetDirectory = Path.Combine(Environment.CurrentDirectory, VideoAppAdapterHandler.OriginName); + if (!Directory.Exists(targetDirectory)) + Directory.CreateDirectory(targetDirectory); + + var fileName = Path.Combine(targetDirectory, $"摄像头查看_{VideoAppAdapterHandler.OriginName}_{DateTime.Now.ToString("yyyy-MM-dd hhmmss")}.avi"); + + var videoWriter = new VideoFileWriter(); + videoWriter.Open(fileName, _videoFrameWidth, _videoFrameHeight, 10, VideoCodec.H264); + + do + { + if (!_videoFrame.IsNull()) + { + lock (this) + videoWriter.WriteVideoFrame(_videoFrame); + GC.Collect(); + } + await Task.Delay(100); //帧率控制,每秒10帧,防止写入过快 + } while (!_stop); + videoWriter.Close(); + } + private void ShowTip(string str) { if (pictureBox.Image != null) @@ -141,6 +210,7 @@ namespace SiMay.RemoteMonitor.Application private void VedioManager_FormClosing(object sender, FormClosingEventArgs e) { + _stop = true; VideoAppAdapterHandler.OnImageFrameHandlerEvent -= OnImageFrameHandlerEvent; VideoAppAdapterHandler.OnCameraNotStartupHandlerEvent -= OnCameraNotStartupHandlerEvent; VideoAppAdapterHandler.CloseSession(); diff --git a/SiMay.RemoteMonitor/Helper/KeygenHelper.cs b/SiMay.RemoteMonitor/Helper/KeygenHelper.cs new file mode 100644 index 0000000..1bc1e29 --- /dev/null +++ b/SiMay.RemoteMonitor/Helper/KeygenHelper.cs @@ -0,0 +1,35 @@ +using SiMay.Basic; +using System; +using System.Collections.Generic; +using System.Linq; +using System.Management; +using System.Text; +using System.Threading.Tasks; + +namespace SiMay.RemoteMonitor +{ + class KeygenHelper + { + private static string GetDiskVolumeSerialNumber() + { + ManagementObject disk = new ManagementObject("win32_logicaldisk.deviceid=\"c:\""); + disk.Get(); + return disk.GetPropertyValue("VolumeSerialNumber").ToString(); + } + + private static string GetCpuSerialNumber() + { + string strCpu = null; + ManagementClass myCpu = new ManagementClass("win32_Processor"); + ManagementObjectCollection myCpuCollection = myCpu.GetInstances(); + foreach (ManagementObject myObject in myCpuCollection) + { + strCpu = myObject.Properties["Processorid"].Value.ToString(); + } + return strCpu; + } + + public static string GetRegSerializeKey() + => GetDiskVolumeSerialNumber() + GetCpuSerialNumber() + Environment.MachineName; + } +} diff --git a/SiMay.RemoteMonitor/Helper/PCMStreamToWavHelper.cs b/SiMay.RemoteMonitor/Helper/PCMStreamToWavHelper.cs new file mode 100644 index 0000000..7d69e6f --- /dev/null +++ b/SiMay.RemoteMonitor/Helper/PCMStreamToWavHelper.cs @@ -0,0 +1,106 @@ +using System; +using System.Collections.Generic; +using System.IO; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace SiMay.RemoteMonitor +{ + public class PCMStreamToWavHelper + { + private BinaryWriter _binaryWriter; + private FileStream _fileStream; + private int _samplesPerSecond; + private short _bitsPerSample; + private short _channels; + private int _dataBufferSize; + private bool _disposed; + /// + /// 累计写入长度 + /// + private int _writeLength = 0; + + public string FileName { get; set; } + + + /// + /// + /// + /// 输出文件名 + /// 采样频率 + /// 每个采样需要的bit数 + /// 声道数量 + public PCMStreamToWavHelper(string fileName, int samplesPerSecond, short bitsPerSample, short channels, int dataBufferSize) + { + _samplesPerSecond = samplesPerSecond; + _bitsPerSample = bitsPerSample; + _channels = channels; + _dataBufferSize = dataBufferSize; + FileName = fileName; + this.CreateSoundFile(fileName); + } + + public void WritePCMDataChunk(byte[] data) + { + if (_disposed) + return; + + _writeLength += data.Length; + _binaryWriter.Write(data, 0, data.Length); + } + + private void CreateSoundFile(string path) + { + _fileStream = new FileStream(path, FileMode.Create); + + _binaryWriter = new BinaryWriter(_fileStream); + + //Set up file with RIFF chunk info. 每个WAVE文件的头四个字节便是“RIFF”。 + char[] ChunkRiff = { 'R', 'I', 'F', 'F' }; + char[] ChunkType = { 'W', 'A', 'V', 'E' }; + char[] ChunkFmt = { 'f', 'm', 't', ' ' }; + char[] ChunkData = { 'd', 'a', 't', 'a' }; + + short shPad = 1; // File padding + + int nFormatChunkLength = 0x10; // Format chunk length. + + int nLength = 0; // File length, minus first 8 bytes of RIFF description. This will be filled in later. + + // 一个样本点的字节数目 + short shBytesPerSample = 2; + + // RIFF 块 + _binaryWriter.Write(ChunkRiff); + _binaryWriter.Write(nLength); + _binaryWriter.Write(ChunkType); + + // WAVE块 + _binaryWriter.Write(ChunkFmt); + _binaryWriter.Write(nFormatChunkLength); + _binaryWriter.Write(shPad); + + + _binaryWriter.Write(_channels); // Mono,声道数目,1-- 单声道;2-- 双声道 + _binaryWriter.Write(_samplesPerSecond);// 16KHz 采样频率 + _binaryWriter.Write(_dataBufferSize); //每秒所需字节数 + _binaryWriter.Write(shBytesPerSample);//数据块对齐单位(每个采样需要的字节数) + _binaryWriter.Write(_bitsPerSample); // 16Bit,每个采样需要的bit数 + + // 数据块 + _binaryWriter.Write(ChunkData); + _binaryWriter.Write((int)0); // The sample length will be written in later. + } + + public void Close() + { + _disposed = true; + _binaryWriter.Seek(4, SeekOrigin.Begin); + _binaryWriter.Write(_writeLength + 36); // 写文件长度 + _binaryWriter.Seek(40, SeekOrigin.Begin); + _binaryWriter.Write(_writeLength); + _fileStream.Close(); + } + } +} diff --git a/SiMay.RemoteMonitor/MainApplication/MainApplication.Designer.cs b/SiMay.RemoteMonitor/MainApplication/MainApplication.Designer.cs index 4723c08..e7629b0 100644 --- a/SiMay.RemoteMonitor/MainApplication/MainApplication.Designer.cs +++ b/SiMay.RemoteMonitor/MainApplication/MainApplication.Designer.cs @@ -158,48 +158,48 @@ this.取消选择ToolStripMenuItem}); this.cmdContext.Name = "CmdContext"; this.cmdContext.RenderMode = System.Windows.Forms.ToolStripRenderMode.Professional; - this.cmdContext.Size = new System.Drawing.Size(137, 258); + this.cmdContext.Size = new System.Drawing.Size(154, 280); this.cmdContext.Opening += new System.ComponentModel.CancelEventHandler(this.CmdContext_Opening); // // toolStripMenuItem11 // this.toolStripMenuItem11.Name = "toolStripMenuItem11"; - this.toolStripMenuItem11.Size = new System.Drawing.Size(136, 22); + this.toolStripMenuItem11.Size = new System.Drawing.Size(153, 24); this.toolStripMenuItem11.Text = "桌面记录"; this.toolStripMenuItem11.Click += new System.EventHandler(this.toolStripMenuItem11_Click); // // toolStripMenuItem6 // this.toolStripMenuItem6.Name = "toolStripMenuItem6"; - this.toolStripMenuItem6.Size = new System.Drawing.Size(136, 22); + this.toolStripMenuItem6.Size = new System.Drawing.Size(153, 24); this.toolStripMenuItem6.Text = "打开网页"; this.toolStripMenuItem6.Click += new System.EventHandler(this.toolStripMenuItem6_Click_1); // // toolStripMenuItem1 // this.toolStripMenuItem1.Name = "toolStripMenuItem1"; - this.toolStripMenuItem1.Size = new System.Drawing.Size(136, 22); + this.toolStripMenuItem1.Size = new System.Drawing.Size(153, 24); this.toolStripMenuItem1.Text = "下载执行"; this.toolStripMenuItem1.Click += new System.EventHandler(this.RemoteDownloadExecete); // // 发送信息ToolStripMenuItem // this.发送信息ToolStripMenuItem.Name = "发送信息ToolStripMenuItem"; - this.发送信息ToolStripMenuItem.Size = new System.Drawing.Size(136, 22); + this.发送信息ToolStripMenuItem.Size = new System.Drawing.Size(153, 24); this.发送信息ToolStripMenuItem.Text = "发送信息"; this.发送信息ToolStripMenuItem.Click += new System.EventHandler(this.SendMessageBox); // // 备注更改ToolStripMenuItem // this.备注更改ToolStripMenuItem.Name = "备注更改ToolStripMenuItem"; - this.备注更改ToolStripMenuItem.Size = new System.Drawing.Size(136, 22); + this.备注更改ToolStripMenuItem.Size = new System.Drawing.Size(153, 24); this.备注更改ToolStripMenuItem.Text = "备注更改"; this.备注更改ToolStripMenuItem.Click += new System.EventHandler(this.ModifyRemark); // // toolStripMenuItem7 // this.toolStripMenuItem7.Name = "toolStripMenuItem7"; - this.toolStripMenuItem7.Size = new System.Drawing.Size(136, 22); + this.toolStripMenuItem7.Size = new System.Drawing.Size(153, 24); this.toolStripMenuItem7.Text = "分组更改"; this.toolStripMenuItem7.Click += new System.EventHandler(this.ToolStripMenuItem7_Click); // @@ -222,141 +222,141 @@ this.toolStripSeparator3, this.卸载控制端ToolStripMenuItem}); this.会话管理ToolStripMenuItem.Name = "会话管理ToolStripMenuItem"; - this.会话管理ToolStripMenuItem.Size = new System.Drawing.Size(136, 22); + this.会话管理ToolStripMenuItem.Size = new System.Drawing.Size(153, 24); this.会话管理ToolStripMenuItem.Text = "会话管理"; // // updateClient // this.updateClient.Name = "updateClient"; - this.updateClient.Size = new System.Drawing.Size(136, 22); + this.updateClient.Size = new System.Drawing.Size(167, 26); this.updateClient.Text = "远程更新"; this.updateClient.Click += new System.EventHandler(this.UpdateClient_Click); // // toolStripMenuItem8 // this.toolStripMenuItem8.Name = "toolStripMenuItem8"; - this.toolStripMenuItem8.Size = new System.Drawing.Size(136, 22); + this.toolStripMenuItem8.Size = new System.Drawing.Size(167, 26); this.toolStripMenuItem8.Text = "重新载入"; this.toolStripMenuItem8.Click += new System.EventHandler(this.ToolStripMenuItem8_Click); // // toolStripSeparator6 // this.toolStripSeparator6.Name = "toolStripSeparator6"; - this.toolStripSeparator6.Size = new System.Drawing.Size(133, 6); + this.toolStripSeparator6.Size = new System.Drawing.Size(164, 6); // // 关闭计算机ToolStripMenuItem // this.关闭计算机ToolStripMenuItem.Name = "关闭计算机ToolStripMenuItem"; - this.关闭计算机ToolStripMenuItem.Size = new System.Drawing.Size(136, 22); + this.关闭计算机ToolStripMenuItem.Size = new System.Drawing.Size(167, 26); this.关闭计算机ToolStripMenuItem.Text = "关闭计算机"; this.关闭计算机ToolStripMenuItem.Click += new System.EventHandler(this.RemoteShutdown); // // 重启计算机ToolStripMenuItem // this.重启计算机ToolStripMenuItem.Name = "重启计算机ToolStripMenuItem"; - this.重启计算机ToolStripMenuItem.Size = new System.Drawing.Size(136, 22); + this.重启计算机ToolStripMenuItem.Size = new System.Drawing.Size(167, 26); this.重启计算机ToolStripMenuItem.Text = "重启计算机"; this.重启计算机ToolStripMenuItem.Click += new System.EventHandler(this.RemoteReboot); // // toolStripSeparator8 // this.toolStripSeparator8.Name = "toolStripSeparator8"; - this.toolStripSeparator8.Size = new System.Drawing.Size(133, 6); + this.toolStripSeparator8.Size = new System.Drawing.Size(164, 6); // // installServiceMenuItem // this.installServiceMenuItem.Name = "installServiceMenuItem"; - this.installServiceMenuItem.Size = new System.Drawing.Size(136, 22); + this.installServiceMenuItem.Size = new System.Drawing.Size(167, 26); this.installServiceMenuItem.Text = "服务安装"; this.installServiceMenuItem.Click += new System.EventHandler(this.installServiceMenuItem_Click); // // unInstallServiceMenuItem // this.unInstallServiceMenuItem.Name = "unInstallServiceMenuItem"; - this.unInstallServiceMenuItem.Size = new System.Drawing.Size(136, 22); + this.unInstallServiceMenuItem.Size = new System.Drawing.Size(167, 26); this.unInstallServiceMenuItem.Text = "服务卸载"; this.unInstallServiceMenuItem.Click += new System.EventHandler(this.unInstallServiceMenuItem_Click); // // toolStripSeparator2 // this.toolStripSeparator2.Name = "toolStripSeparator2"; - this.toolStripSeparator2.Size = new System.Drawing.Size(133, 6); + this.toolStripSeparator2.Size = new System.Drawing.Size(164, 6); // // 开机启动ToolStripMenuItem // this.开机启动ToolStripMenuItem.Name = "开机启动ToolStripMenuItem"; - this.开机启动ToolStripMenuItem.Size = new System.Drawing.Size(136, 22); + this.开机启动ToolStripMenuItem.Size = new System.Drawing.Size(167, 26); this.开机启动ToolStripMenuItem.Text = "注册表启动"; this.开机启动ToolStripMenuItem.Click += new System.EventHandler(this.RemoteStartup); // // 取消自启动ToolStripMenuItem // this.取消自启动ToolStripMenuItem.Name = "取消自启动ToolStripMenuItem"; - this.取消自启动ToolStripMenuItem.Size = new System.Drawing.Size(136, 22); + this.取消自启动ToolStripMenuItem.Size = new System.Drawing.Size(167, 26); this.取消自启动ToolStripMenuItem.Text = "取消自启动"; this.取消自启动ToolStripMenuItem.Click += new System.EventHandler(this.RemoteUnStarup); // // 隐藏服务端ToolStripMenuItem // this.隐藏服务端ToolStripMenuItem.Name = "隐藏服务端ToolStripMenuItem"; - this.隐藏服务端ToolStripMenuItem.Size = new System.Drawing.Size(136, 22); + this.隐藏服务端ToolStripMenuItem.Size = new System.Drawing.Size(167, 26); this.隐藏服务端ToolStripMenuItem.Text = "隐藏服务端"; this.隐藏服务端ToolStripMenuItem.Click += new System.EventHandler(this.RemoteHideServiceFile); // // toolStripMenuItem2 // this.toolStripMenuItem2.Name = "toolStripMenuItem2"; - this.toolStripMenuItem2.Size = new System.Drawing.Size(136, 22); + this.toolStripMenuItem2.Size = new System.Drawing.Size(167, 26); this.toolStripMenuItem2.Text = "显示服务端"; this.toolStripMenuItem2.Click += new System.EventHandler(this.ToolStripMenuItem2_Click); // // toolStripSeparator3 // this.toolStripSeparator3.Name = "toolStripSeparator3"; - this.toolStripSeparator3.Size = new System.Drawing.Size(133, 6); + this.toolStripSeparator3.Size = new System.Drawing.Size(164, 6); // // 卸载控制端ToolStripMenuItem // this.卸载控制端ToolStripMenuItem.Name = "卸载控制端ToolStripMenuItem"; - this.卸载控制端ToolStripMenuItem.Size = new System.Drawing.Size(136, 22); + this.卸载控制端ToolStripMenuItem.Size = new System.Drawing.Size(167, 26); this.卸载控制端ToolStripMenuItem.Text = "卸载服务端"; this.卸载控制端ToolStripMenuItem.Click += new System.EventHandler(this.UninstallService); // // toolStripSeparator4 // this.toolStripSeparator4.Name = "toolStripSeparator4"; - this.toolStripSeparator4.Size = new System.Drawing.Size(133, 6); + this.toolStripSeparator4.Size = new System.Drawing.Size(150, 6); // // toolStripMenuItem4 // this.toolStripMenuItem4.Name = "toolStripMenuItem4"; - this.toolStripMenuItem4.Size = new System.Drawing.Size(136, 22); + this.toolStripMenuItem4.Size = new System.Drawing.Size(153, 24); this.toolStripMenuItem4.Text = "开启屏幕墙"; this.toolStripMenuItem4.Click += new System.EventHandler(this.toolStripMenuItem4_Click); // // toolStripMenuItem5 // this.toolStripMenuItem5.Name = "toolStripMenuItem5"; - this.toolStripMenuItem5.Size = new System.Drawing.Size(136, 22); + this.toolStripMenuItem5.Size = new System.Drawing.Size(153, 24); this.toolStripMenuItem5.Text = "关闭屏幕墙"; this.toolStripMenuItem5.Click += new System.EventHandler(this.toolStripMenuItem5_Click); // // toolStripSeparator1 // this.toolStripSeparator1.Name = "toolStripSeparator1"; - this.toolStripSeparator1.Size = new System.Drawing.Size(133, 6); + this.toolStripSeparator1.Size = new System.Drawing.Size(150, 6); // // 选择全部ToolStripMenuItem // this.选择全部ToolStripMenuItem.Name = "选择全部ToolStripMenuItem"; - this.选择全部ToolStripMenuItem.Size = new System.Drawing.Size(136, 22); + this.选择全部ToolStripMenuItem.Size = new System.Drawing.Size(153, 24); this.选择全部ToolStripMenuItem.Text = "选择全部"; this.选择全部ToolStripMenuItem.Click += new System.EventHandler(this.OnlineList_OnSelected); // // 取消选择ToolStripMenuItem // this.取消选择ToolStripMenuItem.Name = "取消选择ToolStripMenuItem"; - this.取消选择ToolStripMenuItem.Size = new System.Drawing.Size(136, 22); + this.取消选择ToolStripMenuItem.Size = new System.Drawing.Size(153, 24); this.取消选择ToolStripMenuItem.Text = "取消选择"; this.取消选择ToolStripMenuItem.Click += new System.EventHandler(this.OnileList_OnUnSelected); // @@ -369,33 +369,34 @@ this.清空日志ToolStripMenuItem1}); this.logsContext.Name = "logsContext"; this.logsContext.RenderMode = System.Windows.Forms.ToolStripRenderMode.Professional; - this.logsContext.Size = new System.Drawing.Size(125, 70); + this.logsContext.Size = new System.Drawing.Size(139, 76); // // 复制日志ToolStripMenuItem // this.复制日志ToolStripMenuItem.Name = "复制日志ToolStripMenuItem"; - this.复制日志ToolStripMenuItem.Size = new System.Drawing.Size(124, 22); + this.复制日志ToolStripMenuItem.Size = new System.Drawing.Size(138, 24); this.复制日志ToolStripMenuItem.Text = "复制日志"; this.复制日志ToolStripMenuItem.Click += new System.EventHandler(this.CopyRuningLog); // // 删除日志ToolStripMenuItem // this.删除日志ToolStripMenuItem.Name = "删除日志ToolStripMenuItem"; - this.删除日志ToolStripMenuItem.Size = new System.Drawing.Size(124, 22); + this.删除日志ToolStripMenuItem.Size = new System.Drawing.Size(138, 24); this.删除日志ToolStripMenuItem.Text = "删除日志"; this.删除日志ToolStripMenuItem.Click += new System.EventHandler(this.DeleteRuningLog); // // 清空日志ToolStripMenuItem1 // this.清空日志ToolStripMenuItem1.Name = "清空日志ToolStripMenuItem1"; - this.清空日志ToolStripMenuItem1.Size = new System.Drawing.Size(124, 22); + this.清空日志ToolStripMenuItem1.Size = new System.Drawing.Size(138, 24); this.清空日志ToolStripMenuItem1.Text = "清空日志"; this.清空日志ToolStripMenuItem1.Click += new System.EventHandler(this.ClearRuningLog); // // splitContainer1 // this.splitContainer1.Dock = System.Windows.Forms.DockStyle.Fill; - this.splitContainer1.Location = new System.Drawing.Point(0, 81); + this.splitContainer1.Location = new System.Drawing.Point(0, 87); + this.splitContainer1.Margin = new System.Windows.Forms.Padding(4); this.splitContainer1.Name = "splitContainer1"; this.splitContainer1.Orientation = System.Windows.Forms.Orientation.Horizontal; // @@ -407,8 +408,8 @@ // splitContainer1.Panel2 // this.splitContainer1.Panel2.Controls.Add(this.splitContainer); - this.splitContainer1.Size = new System.Drawing.Size(1107, 647); - this.splitContainer1.SplitterDistance = 468; + this.splitContainer1.Size = new System.Drawing.Size(1476, 825); + this.splitContainer1.SplitterDistance = 596; this.splitContainer1.SplitterWidth = 1; this.splitContainer1.TabIndex = 7; // @@ -420,7 +421,7 @@ this.desktopViewLayout.Location = new System.Drawing.Point(0, 0); this.desktopViewLayout.Margin = new System.Windows.Forms.Padding(0); this.desktopViewLayout.Name = "desktopViewLayout"; - this.desktopViewLayout.Size = new System.Drawing.Size(1107, 444); + this.desktopViewLayout.Size = new System.Drawing.Size(1476, 566); this.desktopViewLayout.TabIndex = 3; this.desktopViewLayout.Resize += new System.EventHandler(this.desktopViewLayout_Resize); // @@ -439,18 +440,20 @@ this.panel1.Controls.Add(this.label1); this.panel1.Controls.Add(this.rowtrackBar); this.panel1.Dock = System.Windows.Forms.DockStyle.Bottom; - this.panel1.Location = new System.Drawing.Point(0, 444); + this.panel1.Location = new System.Drawing.Point(0, 566); + this.panel1.Margin = new System.Windows.Forms.Padding(4); this.panel1.Name = "panel1"; - this.panel1.Size = new System.Drawing.Size(1107, 24); + this.panel1.Size = new System.Drawing.Size(1476, 30); this.panel1.TabIndex = 4; // // linkLabel2 // this.linkLabel2.Anchor = ((System.Windows.Forms.AnchorStyles)((System.Windows.Forms.AnchorStyles.Bottom | System.Windows.Forms.AnchorStyles.Right))); this.linkLabel2.AutoSize = true; - this.linkLabel2.Location = new System.Drawing.Point(1048, 6); + this.linkLabel2.Location = new System.Drawing.Point(1397, 8); + this.linkLabel2.Margin = new System.Windows.Forms.Padding(4, 0, 4, 0); this.linkLabel2.Name = "linkLabel2"; - this.linkLabel2.Size = new System.Drawing.Size(53, 12); + this.linkLabel2.Size = new System.Drawing.Size(67, 15); this.linkLabel2.TabIndex = 13; this.linkLabel2.TabStop = true; this.linkLabel2.Text = "视图设置"; @@ -460,9 +463,10 @@ // this.label3.Anchor = ((System.Windows.Forms.AnchorStyles)((System.Windows.Forms.AnchorStyles.Bottom | System.Windows.Forms.AnchorStyles.Right))); this.label3.AutoSize = true; - this.label3.Location = new System.Drawing.Point(542, 6); + this.label3.Location = new System.Drawing.Point(723, 8); + this.label3.Margin = new System.Windows.Forms.Padding(4, 0, 4, 0); this.label3.Name = "label3"; - this.label3.Size = new System.Drawing.Size(35, 12); + this.label3.Size = new System.Drawing.Size(45, 15); this.label3.TabIndex = 12; this.label3.Text = "分组:"; // @@ -474,17 +478,19 @@ this.groupBox.FormattingEnabled = true; this.groupBox.Items.AddRange(new object[] { "全部"}); - this.groupBox.Location = new System.Drawing.Point(578, 3); + this.groupBox.Location = new System.Drawing.Point(771, 4); + this.groupBox.Margin = new System.Windows.Forms.Padding(4); this.groupBox.Name = "groupBox"; - this.groupBox.Size = new System.Drawing.Size(115, 20); + this.groupBox.Size = new System.Drawing.Size(152, 23); this.groupBox.TabIndex = 11; this.groupBox.SelectedIndexChanged += new System.EventHandler(this.GroupBox_SelectedIndexChanged); // // button2 // - this.button2.Location = new System.Drawing.Point(66, 2); + this.button2.Location = new System.Drawing.Point(88, 2); + this.button2.Margin = new System.Windows.Forms.Padding(4); this.button2.Name = "button2"; - this.button2.Size = new System.Drawing.Size(56, 20); + this.button2.Size = new System.Drawing.Size(75, 25); this.button2.TabIndex = 8; this.button2.Text = "反选"; this.button2.UseVisualStyleBackColor = true; @@ -492,9 +498,10 @@ // // button1 // - this.button1.Location = new System.Drawing.Point(4, 2); + this.button1.Location = new System.Drawing.Point(5, 2); + this.button1.Margin = new System.Windows.Forms.Padding(4); this.button1.Name = "button1"; - this.button1.Size = new System.Drawing.Size(56, 20); + this.button1.Size = new System.Drawing.Size(75, 25); this.button1.TabIndex = 7; this.button1.Text = "全选"; this.button1.UseVisualStyleBackColor = true; @@ -504,9 +511,10 @@ // this.viewColumn.Anchor = ((System.Windows.Forms.AnchorStyles)((System.Windows.Forms.AnchorStyles.Bottom | System.Windows.Forms.AnchorStyles.Right))); this.viewColumn.AutoSize = true; - this.viewColumn.Location = new System.Drawing.Point(963, 6); + this.viewColumn.Location = new System.Drawing.Point(1284, 8); + this.viewColumn.Margin = new System.Windows.Forms.Padding(4, 0, 4, 0); this.viewColumn.Name = "viewColumn"; - this.viewColumn.Size = new System.Drawing.Size(11, 12); + this.viewColumn.Size = new System.Drawing.Size(15, 15); this.viewColumn.TabIndex = 6; this.viewColumn.Text = "3"; // @@ -514,9 +522,10 @@ // this.fsd.Anchor = ((System.Windows.Forms.AnchorStyles)((System.Windows.Forms.AnchorStyles.Bottom | System.Windows.Forms.AnchorStyles.Right))); this.fsd.AutoSize = true; - this.fsd.Location = new System.Drawing.Point(698, 6); + this.fsd.Location = new System.Drawing.Point(931, 8); + this.fsd.Margin = new System.Windows.Forms.Padding(4, 0, 4, 0); this.fsd.Name = "fsd"; - this.fsd.Size = new System.Drawing.Size(47, 12); + this.fsd.Size = new System.Drawing.Size(60, 15); this.fsd.TabIndex = 5; this.fsd.Text = "视图列:"; // @@ -524,9 +533,10 @@ // this.viewRow.Anchor = ((System.Windows.Forms.AnchorStyles)((System.Windows.Forms.AnchorStyles.Bottom | System.Windows.Forms.AnchorStyles.Right))); this.viewRow.AutoSize = true; - this.viewRow.Location = new System.Drawing.Point(816, 6); + this.viewRow.Location = new System.Drawing.Point(1088, 8); + this.viewRow.Margin = new System.Windows.Forms.Padding(4, 0, 4, 0); this.viewRow.Name = "viewRow"; - this.viewRow.Size = new System.Drawing.Size(11, 12); + this.viewRow.Size = new System.Drawing.Size(15, 15); this.viewRow.TabIndex = 4; this.viewRow.Text = "4"; // @@ -534,11 +544,12 @@ // this.columntrackBar.Anchor = ((System.Windows.Forms.AnchorStyles)((System.Windows.Forms.AnchorStyles.Bottom | System.Windows.Forms.AnchorStyles.Right))); this.columntrackBar.AutoSize = false; - this.columntrackBar.Location = new System.Drawing.Point(751, 5); + this.columntrackBar.Location = new System.Drawing.Point(1001, 6); + this.columntrackBar.Margin = new System.Windows.Forms.Padding(4); this.columntrackBar.Maximum = 50; this.columntrackBar.Minimum = 1; this.columntrackBar.Name = "columntrackBar"; - this.columntrackBar.Size = new System.Drawing.Size(71, 17); + this.columntrackBar.Size = new System.Drawing.Size(95, 21); this.columntrackBar.TabIndex = 3; this.columntrackBar.TickStyle = System.Windows.Forms.TickStyle.None; this.columntrackBar.Value = 4; @@ -548,9 +559,10 @@ // this.linkLabel1.Anchor = ((System.Windows.Forms.AnchorStyles)((System.Windows.Forms.AnchorStyles.Bottom | System.Windows.Forms.AnchorStyles.Right))); this.linkLabel1.AutoSize = true; - this.linkLabel1.Location = new System.Drawing.Point(988, 6); + this.linkLabel1.Location = new System.Drawing.Point(1317, 8); + this.linkLabel1.Margin = new System.Windows.Forms.Padding(4, 0, 4, 0); this.linkLabel1.Name = "linkLabel1"; - this.linkLabel1.Size = new System.Drawing.Size(53, 12); + this.linkLabel1.Size = new System.Drawing.Size(67, 15); this.linkLabel1.TabIndex = 2; this.linkLabel1.TabStop = true; this.linkLabel1.Text = "保存设置"; @@ -560,9 +572,10 @@ // this.label1.Anchor = ((System.Windows.Forms.AnchorStyles)((System.Windows.Forms.AnchorStyles.Bottom | System.Windows.Forms.AnchorStyles.Right))); this.label1.AutoSize = true; - this.label1.Location = new System.Drawing.Point(839, 6); + this.label1.Location = new System.Drawing.Point(1119, 8); + this.label1.Margin = new System.Windows.Forms.Padding(4, 0, 4, 0); this.label1.Name = "label1"; - this.label1.Size = new System.Drawing.Size(47, 12); + this.label1.Size = new System.Drawing.Size(60, 15); this.label1.TabIndex = 1; this.label1.Text = "视图行:"; // @@ -570,11 +583,12 @@ // this.rowtrackBar.Anchor = ((System.Windows.Forms.AnchorStyles)((System.Windows.Forms.AnchorStyles.Bottom | System.Windows.Forms.AnchorStyles.Right))); this.rowtrackBar.AutoSize = false; - this.rowtrackBar.Location = new System.Drawing.Point(890, 5); + this.rowtrackBar.Location = new System.Drawing.Point(1187, 6); + this.rowtrackBar.Margin = new System.Windows.Forms.Padding(4); this.rowtrackBar.Maximum = 50; this.rowtrackBar.Minimum = 1; this.rowtrackBar.Name = "rowtrackBar"; - this.rowtrackBar.Size = new System.Drawing.Size(76, 17); + this.rowtrackBar.Size = new System.Drawing.Size(101, 21); this.rowtrackBar.TabIndex = 0; this.rowtrackBar.TickStyle = System.Windows.Forms.TickStyle.None; this.rowtrackBar.Value = 3; @@ -584,7 +598,7 @@ // this.splitContainer.Dock = System.Windows.Forms.DockStyle.Fill; this.splitContainer.Location = new System.Drawing.Point(0, 0); - this.splitContainer.Margin = new System.Windows.Forms.Padding(2, 2, 2, 2); + this.splitContainer.Margin = new System.Windows.Forms.Padding(3, 2, 3, 2); this.splitContainer.Name = "splitContainer"; // // splitContainer.Panel1 @@ -594,8 +608,8 @@ // splitContainer.Panel2 // this.splitContainer.Panel2.Controls.Add(this.tabControl1); - this.splitContainer.Size = new System.Drawing.Size(1107, 178); - this.splitContainer.SplitterDistance = 276; + this.splitContainer.Size = new System.Drawing.Size(1476, 228); + this.splitContainer.SplitterDistance = 366; this.splitContainer.SplitterWidth = 1; this.splitContainer.TabIndex = 0; // @@ -605,9 +619,10 @@ this.tabControl2.Controls.Add(this.tabPage2); this.tabControl2.Dock = System.Windows.Forms.DockStyle.Fill; this.tabControl2.Location = new System.Drawing.Point(0, 0); + this.tabControl2.Margin = new System.Windows.Forms.Padding(4); this.tabControl2.Name = "tabControl2"; this.tabControl2.SelectedIndex = 0; - this.tabControl2.Size = new System.Drawing.Size(276, 178); + this.tabControl2.Size = new System.Drawing.Size(366, 228); this.tabControl2.SizeMode = System.Windows.Forms.TabSizeMode.Fixed; this.tabControl2.TabIndex = 1; // @@ -615,9 +630,10 @@ // this.tabPage2.Controls.Add(this.logList); this.tabPage2.Location = new System.Drawing.Point(4, 4); + this.tabPage2.Margin = new System.Windows.Forms.Padding(4); this.tabPage2.Name = "tabPage2"; - this.tabPage2.Padding = new System.Windows.Forms.Padding(3, 3, 3, 3); - this.tabPage2.Size = new System.Drawing.Size(268, 152); + this.tabPage2.Padding = new System.Windows.Forms.Padding(4); + this.tabPage2.Size = new System.Drawing.Size(358, 199); this.tabPage2.TabIndex = 2; this.tabPage2.Text = "运行日志"; this.tabPage2.UseVisualStyleBackColor = true; @@ -629,9 +645,10 @@ this.logList.Dock = System.Windows.Forms.DockStyle.Fill; this.logList.FullRowSelect = true; this.logList.HideSelection = false; - this.logList.Location = new System.Drawing.Point(3, 3); + this.logList.Location = new System.Drawing.Point(4, 4); + this.logList.Margin = new System.Windows.Forms.Padding(4); this.logList.Name = "logList"; - this.logList.Size = new System.Drawing.Size(262, 146); + this.logList.Size = new System.Drawing.Size(350, 191); this.logList.TabIndex = 0; this.logList.UseCompatibleStateImageBehavior = false; this.logList.UseWindowsThemStyle = true; @@ -644,9 +661,10 @@ this.tabControl1.Controls.Add(this.tabPage1); this.tabControl1.Dock = System.Windows.Forms.DockStyle.Fill; this.tabControl1.Location = new System.Drawing.Point(0, 0); + this.tabControl1.Margin = new System.Windows.Forms.Padding(4); this.tabControl1.Name = "tabControl1"; this.tabControl1.SelectedIndex = 0; - this.tabControl1.Size = new System.Drawing.Size(830, 178); + this.tabControl1.Size = new System.Drawing.Size(1109, 228); this.tabControl1.SizeMode = System.Windows.Forms.TabSizeMode.Fixed; this.tabControl1.TabIndex = 0; // @@ -654,9 +672,10 @@ // this.tabPage1.Controls.Add(this.servicesOnlineList); this.tabPage1.Location = new System.Drawing.Point(4, 4); + this.tabPage1.Margin = new System.Windows.Forms.Padding(4); this.tabPage1.Name = "tabPage1"; - this.tabPage1.Padding = new System.Windows.Forms.Padding(3, 3, 3, 3); - this.tabPage1.Size = new System.Drawing.Size(822, 152); + this.tabPage1.Padding = new System.Windows.Forms.Padding(4); + this.tabPage1.Size = new System.Drawing.Size(1101, 199); this.tabPage1.TabIndex = 2; this.tabPage1.Text = "在线列表"; this.tabPage1.UseVisualStyleBackColor = true; @@ -669,9 +688,10 @@ this.servicesOnlineList.Dock = System.Windows.Forms.DockStyle.Fill; this.servicesOnlineList.FullRowSelect = true; this.servicesOnlineList.HideSelection = false; - this.servicesOnlineList.Location = new System.Drawing.Point(3, 3); + this.servicesOnlineList.Location = new System.Drawing.Point(4, 4); + this.servicesOnlineList.Margin = new System.Windows.Forms.Padding(4); this.servicesOnlineList.Name = "servicesOnlineList"; - this.servicesOnlineList.Size = new System.Drawing.Size(816, 146); + this.servicesOnlineList.Size = new System.Drawing.Size(1093, 191); this.servicesOnlineList.TabIndex = 0; this.servicesOnlineList.UseCompatibleStateImageBehavior = false; this.servicesOnlineList.UseWindowsThemStyle = false; @@ -695,10 +715,11 @@ this.stripPort, this.toolStripStatusLabel6, this.stripConnectedNum}); - this.statusStrip1.Location = new System.Drawing.Point(0, 728); + this.statusStrip1.Location = new System.Drawing.Point(0, 912); this.statusStrip1.Name = "statusStrip1"; + this.statusStrip1.Padding = new System.Windows.Forms.Padding(1, 0, 19, 0); this.statusStrip1.RenderMode = System.Windows.Forms.ToolStripRenderMode.ManagerRenderMode; - this.statusStrip1.Size = new System.Drawing.Size(1107, 26); + this.statusStrip1.Size = new System.Drawing.Size(1476, 30); this.statusStrip1.TabIndex = 2; this.statusStrip1.Text = "statusStrip1"; // @@ -706,56 +727,56 @@ // this.toolStripStatusLabel1.Font = new System.Drawing.Font("微软雅黑", 9F, System.Drawing.FontStyle.Regular, System.Drawing.GraphicsUnit.Point, ((byte)(134))); this.toolStripStatusLabel1.Name = "toolStripStatusLabel1"; - this.toolStripStatusLabel1.Size = new System.Drawing.Size(71, 21); + this.toolStripStatusLabel1.Size = new System.Drawing.Size(88, 24); this.toolStripStatusLabel1.Text = "服务器地址:"; // // stripHost // this.stripHost.Font = new System.Drawing.Font("微软雅黑", 9F, System.Drawing.FontStyle.Regular, System.Drawing.GraphicsUnit.Point, ((byte)(134))); this.stripHost.Name = "stripHost"; - this.stripHost.Size = new System.Drawing.Size(45, 21); + this.stripHost.Size = new System.Drawing.Size(57, 24); this.stripHost.Text = "0.0.0.0"; // // toolStripStatusLabel5 // this.toolStripStatusLabel5.Name = "toolStripStatusLabel5"; - this.toolStripStatusLabel5.Size = new System.Drawing.Size(618, 21); + this.toolStripStatusLabel5.Size = new System.Drawing.Size(873, 24); this.toolStripStatusLabel5.Spring = true; // // toolStripStatusLabel2 // this.toolStripStatusLabel2.Name = "toolStripStatusLabel2"; - this.toolStripStatusLabel2.Size = new System.Drawing.Size(35, 21); + this.toolStripStatusLabel2.Size = new System.Drawing.Size(43, 24); this.toolStripStatusLabel2.Text = "上传:"; // // struflow // this.struflow.Name = "struflow"; - this.struflow.Size = new System.Drawing.Size(32, 21); + this.struflow.Size = new System.Drawing.Size(40, 24); this.struflow.Text = "0.00"; // // toolStripStatusLabel4 // this.toolStripStatusLabel4.Name = "toolStripStatusLabel4"; - this.toolStripStatusLabel4.Size = new System.Drawing.Size(36, 21); + this.toolStripStatusLabel4.Size = new System.Drawing.Size(43, 24); this.toolStripStatusLabel4.Text = "KB/S"; // // toolStripStatusLabel7 // this.toolStripStatusLabel7.Name = "toolStripStatusLabel7"; - this.toolStripStatusLabel7.Size = new System.Drawing.Size(35, 21); + this.toolStripStatusLabel7.Size = new System.Drawing.Size(43, 24); this.toolStripStatusLabel7.Text = "下传:"; // // strdownflow // this.strdownflow.Name = "strdownflow"; - this.strdownflow.Size = new System.Drawing.Size(32, 21); + this.strdownflow.Size = new System.Drawing.Size(40, 24); this.strdownflow.Text = "0.00"; // // toolStripStatusLabel8 // this.toolStripStatusLabel8.Name = "toolStripStatusLabel8"; - this.toolStripStatusLabel8.Size = new System.Drawing.Size(36, 21); + this.toolStripStatusLabel8.Size = new System.Drawing.Size(43, 24); this.toolStripStatusLabel8.Text = "KB/S"; // // toolStripStatusLabel3 @@ -763,14 +784,14 @@ this.toolStripStatusLabel3.BorderSides = System.Windows.Forms.ToolStripStatusLabelBorderSides.Left; this.toolStripStatusLabel3.Font = new System.Drawing.Font("微软雅黑", 9F, System.Drawing.FontStyle.Regular, System.Drawing.GraphicsUnit.Point, ((byte)(134))); this.toolStripStatusLabel3.Name = "toolStripStatusLabel3"; - this.toolStripStatusLabel3.Size = new System.Drawing.Size(39, 21); + this.toolStripStatusLabel3.Size = new System.Drawing.Size(47, 24); this.toolStripStatusLabel3.Text = "端口:"; // // stripPort // this.stripPort.Font = new System.Drawing.Font("微软雅黑", 9F, System.Drawing.FontStyle.Regular, System.Drawing.GraphicsUnit.Point, ((byte)(134))); this.stripPort.Name = "stripPort"; - this.stripPort.Size = new System.Drawing.Size(36, 21); + this.stripPort.Size = new System.Drawing.Size(45, 24); this.stripPort.Text = "5200"; // // toolStripStatusLabel6 @@ -778,14 +799,14 @@ this.toolStripStatusLabel6.BorderSides = System.Windows.Forms.ToolStripStatusLabelBorderSides.Left; this.toolStripStatusLabel6.Font = new System.Drawing.Font("微软雅黑", 9F, System.Drawing.FontStyle.Regular, System.Drawing.GraphicsUnit.Point, ((byte)(134))); this.toolStripStatusLabel6.Name = "toolStripStatusLabel6"; - this.toolStripStatusLabel6.Size = new System.Drawing.Size(63, 21); + this.toolStripStatusLabel6.Size = new System.Drawing.Size(77, 24); this.toolStripStatusLabel6.Text = "主机数量:"; // // stripConnectedNum // this.stripConnectedNum.Font = new System.Drawing.Font("微软雅黑", 7.5F, System.Drawing.FontStyle.Regular, System.Drawing.GraphicsUnit.Point, ((byte)(134))); this.stripConnectedNum.Name = "stripConnectedNum"; - this.stripConnectedNum.Size = new System.Drawing.Size(14, 21); + this.stripConnectedNum.Size = new System.Drawing.Size(17, 24); this.stripConnectedNum.Text = "0"; // // toolStrip1 @@ -801,9 +822,9 @@ this.toolStripButton6, this.toolStripButton14, this.toolStripButton8}); - this.toolStrip1.Location = new System.Drawing.Point(0, 25); + this.toolStrip1.Location = new System.Drawing.Point(0, 28); this.toolStrip1.Name = "toolStrip1"; - this.toolStrip1.Size = new System.Drawing.Size(1107, 56); + this.toolStrip1.Size = new System.Drawing.Size(1476, 59); this.toolStrip1.TabIndex = 6; this.toolStrip1.Text = "toolStrip1"; // @@ -813,7 +834,7 @@ this.toolStripButton10.ImageScaling = System.Windows.Forms.ToolStripItemImageScaling.None; this.toolStripButton10.ImageTransparentColor = System.Drawing.Color.Magenta; this.toolStripButton10.Name = "toolStripButton10"; - this.toolStripButton10.Size = new System.Drawing.Size(64, 53); + this.toolStripButton10.Size = new System.Drawing.Size(73, 56); this.toolStripButton10.Text = "系统设置"; this.toolStripButton10.TextImageRelation = System.Windows.Forms.TextImageRelation.ImageAboveText; this.toolStripButton10.Click += new System.EventHandler(this.toolStripButton10_Click); @@ -824,7 +845,7 @@ this.toolStripButton9.ImageScaling = System.Windows.Forms.ToolStripItemImageScaling.None; this.toolStripButton9.ImageTransparentColor = System.Drawing.Color.Magenta; this.toolStripButton9.Name = "toolStripButton9"; - this.toolStripButton9.Size = new System.Drawing.Size(64, 53); + this.toolStripButton9.Size = new System.Drawing.Size(73, 56); this.toolStripButton9.Text = "创建客户"; this.toolStripButton9.TextImageRelation = System.Windows.Forms.TextImageRelation.ImageAboveText; this.toolStripButton9.Click += new System.EventHandler(this.toolStripButton9_Click); @@ -832,7 +853,7 @@ // toolStripSeparator5 // this.toolStripSeparator5.Name = "toolStripSeparator5"; - this.toolStripSeparator5.Size = new System.Drawing.Size(6, 56); + this.toolStripSeparator5.Size = new System.Drawing.Size(6, 59); // // toolStripButton7 // @@ -840,7 +861,7 @@ this.toolStripButton7.ImageScaling = System.Windows.Forms.ToolStripItemImageScaling.None; this.toolStripButton7.ImageTransparentColor = System.Drawing.Color.Magenta; this.toolStripButton7.Name = "toolStripButton7"; - this.toolStripButton7.Size = new System.Drawing.Size(64, 53); + this.toolStripButton7.Size = new System.Drawing.Size(73, 56); this.toolStripButton7.Text = "消息通知"; this.toolStripButton7.TextImageRelation = System.Windows.Forms.TextImageRelation.ImageAboveText; this.toolStripButton7.Click += new System.EventHandler(this.toolStripButton7_Click); @@ -851,7 +872,7 @@ this.toolStripButton6.ImageScaling = System.Windows.Forms.ToolStripItemImageScaling.None; this.toolStripButton6.ImageTransparentColor = System.Drawing.Color.Magenta; this.toolStripButton6.Name = "toolStripButton6"; - this.toolStripButton6.Size = new System.Drawing.Size(64, 53); + this.toolStripButton6.Size = new System.Drawing.Size(73, 56); this.toolStripButton6.Text = "下载执行"; this.toolStripButton6.TextImageRelation = System.Windows.Forms.TextImageRelation.ImageAboveText; this.toolStripButton6.Click += new System.EventHandler(this.toolStripButton6_Click); @@ -862,7 +883,7 @@ this.toolStripButton14.ImageScaling = System.Windows.Forms.ToolStripItemImageScaling.None; this.toolStripButton14.ImageTransparentColor = System.Drawing.Color.Magenta; this.toolStripButton14.Name = "toolStripButton14"; - this.toolStripButton14.Size = new System.Drawing.Size(64, 53); + this.toolStripButton14.Size = new System.Drawing.Size(73, 56); this.toolStripButton14.Text = "关闭屏幕"; this.toolStripButton14.TextImageRelation = System.Windows.Forms.TextImageRelation.ImageAboveText; this.toolStripButton14.Click += new System.EventHandler(this.toolStripButton14_Click); @@ -873,7 +894,7 @@ this.toolStripButton8.ImageScaling = System.Windows.Forms.ToolStripItemImageScaling.None; this.toolStripButton8.ImageTransparentColor = System.Drawing.Color.Magenta; this.toolStripButton8.Name = "toolStripButton8"; - this.toolStripButton8.Size = new System.Drawing.Size(64, 53); + this.toolStripButton8.Size = new System.Drawing.Size(73, 56); this.toolStripButton8.Text = "卸载程序"; this.toolStripButton8.TextImageRelation = System.Windows.Forms.TextImageRelation.ImageAboveText; this.toolStripButton8.Click += new System.EventHandler(this.toolStripButton8_Click); @@ -889,9 +910,9 @@ this.toolStripMenuItem3}); this.menuStrip1.Location = new System.Drawing.Point(0, 0); this.menuStrip1.Name = "menuStrip1"; - this.menuStrip1.Padding = new System.Windows.Forms.Padding(4, 2, 0, 2); + this.menuStrip1.Padding = new System.Windows.Forms.Padding(5, 2, 0, 2); this.menuStrip1.RenderMode = System.Windows.Forms.ToolStripRenderMode.Professional; - this.menuStrip1.Size = new System.Drawing.Size(1107, 25); + this.menuStrip1.Size = new System.Drawing.Size(1476, 28); this.menuStrip1.TabIndex = 0; this.menuStrip1.Text = "menuStrip1"; // @@ -899,7 +920,7 @@ // this.系统设置ToolStripMenuItem.Name = "系统设置ToolStripMenuItem"; this.系统设置ToolStripMenuItem.ShortcutKeys = ((System.Windows.Forms.Keys)((System.Windows.Forms.Keys.Control | System.Windows.Forms.Keys.F))); - this.系统设置ToolStripMenuItem.Size = new System.Drawing.Size(82, 21); + this.系统设置ToolStripMenuItem.Size = new System.Drawing.Size(101, 24); this.系统设置ToolStripMenuItem.Text = "系统设置(&F)"; this.系统设置ToolStripMenuItem.Click += new System.EventHandler(this.SystemOption); // @@ -907,7 +928,7 @@ // this.创建客户ToolStripMenuItem.Name = "创建客户ToolStripMenuItem"; this.创建客户ToolStripMenuItem.ShortcutKeys = ((System.Windows.Forms.Keys)((System.Windows.Forms.Keys.Control | System.Windows.Forms.Keys.E))); - this.创建客户ToolStripMenuItem.Size = new System.Drawing.Size(83, 21); + this.创建客户ToolStripMenuItem.Size = new System.Drawing.Size(101, 24); this.创建客户ToolStripMenuItem.Text = "创建客户(&E)"; this.创建客户ToolStripMenuItem.Click += new System.EventHandler(this.CreateService); // @@ -921,7 +942,7 @@ this.桌面记录查看ToolStripMenuItem}); this.查看ToolStripMenuItem.Name = "查看ToolStripMenuItem"; this.查看ToolStripMenuItem.ShortcutKeys = ((System.Windows.Forms.Keys)((System.Windows.Forms.Keys.Control | System.Windows.Forms.Keys.V))); - this.查看ToolStripMenuItem.Size = new System.Drawing.Size(84, 21); + this.查看ToolStripMenuItem.Size = new System.Drawing.Size(103, 24); this.查看ToolStripMenuItem.Text = "视图查看(&V)"; // // ToolStripMenuItem @@ -929,7 +950,7 @@ this.ToolStripMenuItem.Checked = true; this.ToolStripMenuItem.CheckState = System.Windows.Forms.CheckState.Checked; this.ToolStripMenuItem.Name = "ToolStripMenuItem"; - this.ToolStripMenuItem.Size = new System.Drawing.Size(148, 22); + this.ToolStripMenuItem.Size = new System.Drawing.Size(182, 26); this.ToolStripMenuItem.Text = "工具栏"; this.ToolStripMenuItem.Click += new System.EventHandler(this.ToolStripMenuItem_Click); // @@ -938,7 +959,7 @@ this.statusToolStripMenuItem.Checked = true; this.statusToolStripMenuItem.CheckState = System.Windows.Forms.CheckState.Checked; this.statusToolStripMenuItem.Name = "statusToolStripMenuItem"; - this.statusToolStripMenuItem.Size = new System.Drawing.Size(148, 22); + this.statusToolStripMenuItem.Size = new System.Drawing.Size(182, 26); this.statusToolStripMenuItem.Text = "状态栏"; this.statusToolStripMenuItem.Click += new System.EventHandler(this.statusToolStripMenuItem_Click); // @@ -947,19 +968,19 @@ this.onlineToolStripMenuItem.Checked = true; this.onlineToolStripMenuItem.CheckState = System.Windows.Forms.CheckState.Checked; this.onlineToolStripMenuItem.Name = "onlineToolStripMenuItem"; - this.onlineToolStripMenuItem.Size = new System.Drawing.Size(148, 22); + this.onlineToolStripMenuItem.Size = new System.Drawing.Size(182, 26); this.onlineToolStripMenuItem.Text = "选项栏"; this.onlineToolStripMenuItem.Click += new System.EventHandler(this.onlineToolStripMenuItem_Click); // // toolStripSeparator7 // this.toolStripSeparator7.Name = "toolStripSeparator7"; - this.toolStripSeparator7.Size = new System.Drawing.Size(145, 6); + this.toolStripSeparator7.Size = new System.Drawing.Size(179, 6); // // 桌面记录查看ToolStripMenuItem // this.桌面记录查看ToolStripMenuItem.Name = "桌面记录查看ToolStripMenuItem"; - this.桌面记录查看ToolStripMenuItem.Size = new System.Drawing.Size(148, 22); + this.桌面记录查看ToolStripMenuItem.Size = new System.Drawing.Size(182, 26); this.桌面记录查看ToolStripMenuItem.Text = "桌面记录查看"; this.桌面记录查看ToolStripMenuItem.Click += new System.EventHandler(this.viewReviewToolStripMenuItem_Click); // @@ -967,7 +988,7 @@ // this.锁定ToolStripMenuItem.Name = "锁定ToolStripMenuItem"; this.锁定ToolStripMenuItem.ShortcutKeys = ((System.Windows.Forms.Keys)((System.Windows.Forms.Keys.Control | System.Windows.Forms.Keys.G))); - this.锁定ToolStripMenuItem.Size = new System.Drawing.Size(61, 21); + this.锁定ToolStripMenuItem.Size = new System.Drawing.Size(74, 24); this.锁定ToolStripMenuItem.Text = "锁定(&G)"; this.锁定ToolStripMenuItem.Click += new System.EventHandler(this.lockToolStripMenuItem_Click); // @@ -975,20 +996,22 @@ // this.toolStripMenuItem3.Name = "toolStripMenuItem3"; this.toolStripMenuItem3.ShortcutKeys = ((System.Windows.Forms.Keys)((System.Windows.Forms.Keys.Control | System.Windows.Forms.Keys.H))); - this.toolStripMenuItem3.Size = new System.Drawing.Size(85, 21); + this.toolStripMenuItem3.Size = new System.Drawing.Size(105, 24); this.toolStripMenuItem3.Text = "关于程序(&H)"; + this.toolStripMenuItem3.Visible = false; this.toolStripMenuItem3.Click += new System.EventHandler(this.About); // // MainApplication // - this.AutoScaleDimensions = new System.Drawing.SizeF(6F, 12F); + this.AutoScaleDimensions = new System.Drawing.SizeF(8F, 15F); this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font; - this.ClientSize = new System.Drawing.Size(1107, 754); + this.ClientSize = new System.Drawing.Size(1476, 942); this.Controls.Add(this.splitContainer1); this.Controls.Add(this.statusStrip1); this.Controls.Add(this.toolStrip1); this.Controls.Add(this.menuStrip1); this.MainMenuStrip = this.menuStrip1; + this.Margin = new System.Windows.Forms.Padding(4); this.Name = "MainApplication"; this.StartPosition = System.Windows.Forms.FormStartPosition.CenterScreen; this.FormClosing += new System.Windows.Forms.FormClosingEventHandler(this.MainApplication_FormClosing); diff --git a/SiMay.RemoteMonitor/MainApplication/MainApplication.cs b/SiMay.RemoteMonitor/MainApplication/MainApplication.cs index cdae05a..1f72625 100644 --- a/SiMay.RemoteMonitor/MainApplication/MainApplication.cs +++ b/SiMay.RemoteMonitor/MainApplication/MainApplication.cs @@ -251,10 +251,16 @@ namespace SiMay.RemoteMonitor.MainApplication this._appMainAdapterHandler.OnCreateDesktopViewHandlerEvent += OnCreateDesktopViewHandlerEvent; this._appMainAdapterHandler.OnLoginHandlerEvent += OnLoginHandlerEvent; this._appMainAdapterHandler.OnLoginUpdateHandlerEvent += OnLoginUpdateHandlerEvent; + this._appMainAdapterHandler.OnApplicationCreatedEventHandler += OnApplicationCreatedEventHandler; this._appMainAdapterHandler.OnLogHandlerEvent += OnLogHandlerEvent; this._appMainAdapterHandler.StartApp(); } + private void OnApplicationCreatedEventHandler(IApplication app) + { + + } + private void OnLoginUpdateHandlerEvent(SessionSyncContext syncContext) { var listItem = syncContext.KeyDictions[SysConstantsExtend.SessionListItem].ConvertTo(); ; diff --git a/SiMay.RemoteMonitor/Properties/AssemblyInfo.cs b/SiMay.RemoteMonitor/Properties/AssemblyInfo.cs index d81b740..703bef5 100644 --- a/SiMay.RemoteMonitor/Properties/AssemblyInfo.cs +++ b/SiMay.RemoteMonitor/Properties/AssemblyInfo.cs @@ -32,5 +32,5 @@ using System.Runtime.InteropServices; // 可以指定所有这些值,也可以使用“生成号”和“修订号”的默认值, // 方法是按如下所示使用“*”: // [assembly: AssemblyVersion("1.0.*")] -[assembly: AssemblyVersion("6.0.0.1")] -[assembly: AssemblyFileVersion("6.0.0.1")] +[assembly: AssemblyVersion("6.0.0.2")] +[assembly: AssemblyFileVersion("6.0.0.2")] diff --git a/SiMay.RemoteMonitor/SiMay.RemoteMonitor.csproj b/SiMay.RemoteMonitor/SiMay.RemoteMonitor.csproj index 79ebaa4..c1c592f 100644 --- a/SiMay.RemoteMonitor/SiMay.RemoteMonitor.csproj +++ b/SiMay.RemoteMonitor/SiMay.RemoteMonitor.csproj @@ -13,6 +13,8 @@ 512 + + AnyCPU @@ -45,7 +47,7 @@ true - bin\x86\Debug\ + ..\Bin\ DEBUG;TRACE full x86 @@ -55,7 +57,7 @@ 8.0 - bin\x86\Release\ + ..\Bin\ TRACE true pdbonly @@ -69,10 +71,20 @@ app.manifest + + ..\packages\Accord.3.8.0\lib\net46\Accord.dll + + + ..\packages\Accord.Video.3.8.0\lib\net46\Accord.Video.dll + + + ..\packages\Accord.Video.FFMPEG.3.8.0\lib\net46\Accord.Video.FFMPEG.dll + + @@ -155,10 +167,12 @@ TcpConnectionApplication.cs + + Form @@ -172,6 +186,7 @@ RemoteUpdateServiceForm.cs + @@ -442,6 +457,7 @@ Designer + SettingsSingleFileGenerator Settings.Designer.cs @@ -520,6 +536,15 @@ + + + + 这台计算机上缺少此项目引用的 NuGet 程序包。使用“NuGet 程序包还原”可下载这些程序包。有关更多信息,请参见 http://go.microsoft.com/fwlink/?LinkID=322105。缺少的文件是 {0}。 + + + + +