桌面共享

This commit is contained in:
snltty
2024-04-01 09:49:35 +08:00
parent c3f80b40c0
commit 208e1bffbf
293 changed files with 5880 additions and 3918 deletions

2
.gitignore vendored
View File

@@ -6,4 +6,4 @@ node_modules
/public/*
/cmonitor.volume/x64/*
/cmonitor.killer/x64/*
/x64/*
/x64/*

View File

@@ -70,7 +70,7 @@
- [x] 发送命令执行cmd命令等等
###### 互动
- [x] 互动答题 **winform**
- [x] 屏幕共享,以某一设备为主机,向其它设备共享屏幕,用于演示 **sharpDX** **第一次成功连接服务端后自动恢复**
- [x] 屏幕共享,以某一设备为主机,向其它设备共享屏幕,用于演示 **RDPSession+RDPViewer** **第一次成功连接服务端后自动恢复**
###### 壁纸
- [x] 壁纸程序,为所有设备设置统一壁纸,以程序的方式 **winform** **第一次成功连接服务端后自动恢复**
- [x] 键盘按键,显示键盘按键(当前键盘按键由壁纸程序提供) **win api**
@@ -97,7 +97,7 @@
1. **【--server】** 服务器ip **192.168.1.18**
2. **【--service】** 服务端口 **1802**
3. **【--share-key】** 自定数据共享 **cmonitor/share**
4. **【--share-len】** 数量 **10**默认10项位置0保留1键盘、2壁纸、3锁屏4 SendSAS
4. **【--share-len】** 数量 **100**默认100项位置0保留1键盘、2壁纸、3锁屏4 SendSAS 5 抢答问题, 6 抢答答案, 7 屏幕共享, 8 剪贴板
4. **【--share-item-len】** 每项数据长度 **1024**attr(1)+version(8)+klen(4)+key(klen)+vlen(4)+value(vallen)
###### 服务端

View File

@@ -0,0 +1,60 @@
namespace cmonitor.clipboard.win
{
partial class MainForm
{
/// <summary>
/// Required designer variable.
/// </summary>
private System.ComponentModel.IContainer components = null;
/// <summary>
/// Clean up any resources being used.
/// </summary>
/// <param name="disposing">true if managed resources should be disposed; otherwise, false.</param>
protected override void Dispose(bool disposing)
{
if (disposing && (components != null))
{
components.Dispose();
}
base.Dispose(disposing);
}
#region Windows Form Designer generated code
/// <summary>
/// Required method for Designer support - do not modify
/// the contents of this method with the code editor.
/// </summary>
private void InitializeComponent()
{
System.ComponentModel.ComponentResourceManager resources = new System.ComponentModel.ComponentResourceManager(typeof(MainForm));
textBox1 = new TextBox();
SuspendLayout();
//
// textBox1
//
textBox1.Location = new Point(12, 12);
textBox1.Multiline = true;
textBox1.Name = "textBox1";
textBox1.Size = new Size(261, 287);
textBox1.TabIndex = 0;
//
// MainForm
//
AutoScaleDimensions = new SizeF(7F, 17F);
AutoScaleMode = AutoScaleMode.Font;
ClientSize = new Size(285, 450);
Controls.Add(textBox1);
Icon = (Icon)resources.GetObject("$this.Icon");
Name = "MainForm";
Text = "剪贴板";
ResumeLayout(false);
PerformLayout();
}
#endregion
private TextBox textBox1;
}
}

View File

@@ -0,0 +1,138 @@
using System.Runtime.InteropServices;
namespace cmonitor.clipboard.win
{
public partial class MainForm : Form
{
protected override CreateParams CreateParams
{
get
{
const int WS_EX_APPWINDOW = 0x40000;
const int WS_EX_TOOLWINDOW = 0x80;
CreateParams cp = base.CreateParams;
cp.ExStyle &= (~WS_EX_APPWINDOW);
cp.ExStyle |= WS_EX_TOOLWINDOW;
return cp;
}
}
private IntPtr nextClipboardViewer;
const int WM_DRAWCLIPBOARD = 0x0308;
const uint CF_TEXT = 1;
const uint CF_HDROP = 15;
public MainForm()
{
StartPosition = FormStartPosition.CenterScreen;
MaximizeBox = false;
MinimizeBox = false;
InitializeComponent();
nextClipboardViewer = SetClipboardViewer(this.Handle);
}
protected override void WndProc(ref Message m)
{
base.WndProc(ref m);
if (m.Msg == WM_DRAWCLIPBOARD)
{
OnClipboardChanged();
}
}
private void OnClipboardChanged()
{
if (OpenClipboard(IntPtr.Zero))
{
uint format = 0;
while ((format = EnumClipboardFormats(format)) != 0)
{
switch (format)
{
case CF_TEXT:
HandleTextData();
break;
case CF_HDROP:
HandleFileListData();
break;
}
}
CloseClipboard();
}
}
private void HandleTextData()
{
IntPtr clipboardData = GetClipboardData(CF_TEXT);
if (clipboardData != IntPtr.Zero)
{
string text = Marshal.PtrToStringAnsi(clipboardData);
this.Invoke(() =>
{
textBox1.Text = text;
});
}
}
private void HandleFileListData()
{
IntPtr clipboardData = GetClipboardData(CF_HDROP);
if (clipboardData != IntPtr.Zero)
{
IntPtr fileDropHandle = Marshal.ReadIntPtr(clipboardData);
uint fileCount = DragQueryFile(fileDropHandle, 0xFFFFFFFF, null, 0);
List<string> fileList = new List<string>();
for (uint i = 0; i < fileCount; i++)
{
uint bufferSize = DragQueryFile(fileDropHandle, i, null, 0) + 1;
char[] fileName = new char[bufferSize];
DragQueryFile(fileDropHandle, i, fileName, bufferSize);
string filePath = new string(fileName);
fileList.Add(filePath);
}
DragFinish(fileDropHandle);
this.Invoke(() =>
{
textBox1.Text = string.Join("\r\n", fileList);
});
}
}
[DllImport("user32.dll", SetLastError = true)]
static extern IntPtr SetClipboardViewer(IntPtr hWndNewViewer);
[DllImport("user32.dll", SetLastError = true)]
static extern bool ChangeClipboardChain(IntPtr hWndRemove, IntPtr hWndNewNext);
[DllImport("user32.dll", SetLastError = true)]
static extern IntPtr GetClipboardData(uint uFormat);
[DllImport("user32.dll", SetLastError = true)]
static extern bool IsClipboardFormatAvailable(uint format);
[DllImport("user32.dll", SetLastError = true)]
static extern uint EnumClipboardFormats(uint format);
[DllImport("shell32.dll")]
static extern uint DragQueryFile(IntPtr hDrop, uint iFile, char[] lpszFile, uint cch);
[DllImport("shell32.dll")]
static extern void DragFinish(IntPtr hDrop);
[DllImport("user32.dll", SetLastError = true)]
static extern bool OpenClipboard(IntPtr hWndNewOwner);
[DllImport("user32.dll", SetLastError = true)]
static extern bool CloseClipboard();
[DllImport("kernel32.dll")]
static extern IntPtr GlobalLock(IntPtr hMem);
[DllImport("kernel32.dll")]
static extern bool GlobalUnlock(IntPtr hMem);
}
}

View File

@@ -0,0 +1,17 @@
namespace cmonitor.clipboard.win
{
internal static class Program
{
/// <summary>
/// The main entry point for the application.
/// </summary>
[STAThread]
static void Main()
{
// To customize application configuration such as set high DPI settings or default font,
// see https://aka.ms/applicationconfiguration.
ApplicationConfiguration.Initialize();
Application.Run(new MainForm());
}
}
}

View File

@@ -0,0 +1,17 @@
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<OutputType>WinExe</OutputType>
<TargetFrameworks>net7.0-windows;net8.0-windows</TargetFrameworks>
<Nullable>disable</Nullable>
<UseWindowsForms>true</UseWindowsForms>
<ImplicitUsings>enable</ImplicitUsings>
<ApplicationIcon>favicon.ico</ApplicationIcon>
<ApplicationManifest>app.manifest</ApplicationManifest>
</PropertyGroup>
<ItemGroup>
<Content Include="favicon.ico" />
</ItemGroup>
</Project>

View File

Before

Width:  |  Height:  |  Size: 16 KiB

After

Width:  |  Height:  |  Size: 16 KiB

View File

@@ -43,14 +43,6 @@
shareLen = new TextBox();
label6 = new Label();
shareKey = new TextBox();
label7 = new Label();
wallpaperIndex = new TextBox();
label8 = new Label();
keyboardIndex = new TextBox();
label9 = new Label();
llockIndex = new TextBox();
label10 = new Label();
sasIndex = new TextBox();
label11 = new Label();
machineName = new TextBox();
label12 = new Label();
@@ -60,7 +52,6 @@
label14 = new Label();
screenScale = new TextBox();
installBtn = new Button();
label15 = new Label();
runBtn = new Button();
checkStateBtn = new Button();
label16 = new Label();
@@ -139,46 +130,6 @@
resources.ApplyResources(shareKey, "shareKey");
shareKey.Name = "shareKey";
//
// label7
//
resources.ApplyResources(label7, "label7");
label7.Name = "label7";
//
// wallpaperIndex
//
resources.ApplyResources(wallpaperIndex, "wallpaperIndex");
wallpaperIndex.Name = "wallpaperIndex";
//
// label8
//
resources.ApplyResources(label8, "label8");
label8.Name = "label8";
//
// keyboardIndex
//
resources.ApplyResources(keyboardIndex, "keyboardIndex");
keyboardIndex.Name = "keyboardIndex";
//
// label9
//
resources.ApplyResources(label9, "label9");
label9.Name = "label9";
//
// llockIndex
//
resources.ApplyResources(llockIndex, "llockIndex");
llockIndex.Name = "llockIndex";
//
// label10
//
resources.ApplyResources(label10, "label10");
label10.Name = "label10";
//
// sasIndex
//
resources.ApplyResources(sasIndex, "sasIndex");
sasIndex.Name = "sasIndex";
//
// label11
//
resources.ApplyResources(label11, "label11");
@@ -226,11 +177,6 @@
installBtn.UseVisualStyleBackColor = true;
installBtn.Click += OnInstallClick;
//
// label15
//
resources.ApplyResources(label15, "label15");
label15.Name = "label15";
//
// runBtn
//
resources.ApplyResources(runBtn, "runBtn");
@@ -263,7 +209,6 @@
Controls.Add(shareItemLen);
Controls.Add(checkStateBtn);
Controls.Add(runBtn);
Controls.Add(label15);
Controls.Add(installBtn);
Controls.Add(label14);
Controls.Add(screenScale);
@@ -273,14 +218,6 @@
Controls.Add(reportDelay);
Controls.Add(label11);
Controls.Add(machineName);
Controls.Add(label10);
Controls.Add(sasIndex);
Controls.Add(label9);
Controls.Add(llockIndex);
Controls.Add(label7);
Controls.Add(wallpaperIndex);
Controls.Add(label8);
Controls.Add(keyboardIndex);
Controls.Add(label5);
Controls.Add(shareLen);
Controls.Add(label6);
@@ -315,14 +252,6 @@
private System.Windows.Forms.TextBox shareLen;
private System.Windows.Forms.Label label6;
private System.Windows.Forms.TextBox shareKey;
private System.Windows.Forms.Label label7;
private System.Windows.Forms.TextBox wallpaperIndex;
private System.Windows.Forms.Label label8;
private System.Windows.Forms.TextBox keyboardIndex;
private System.Windows.Forms.Label label9;
private System.Windows.Forms.TextBox llockIndex;
private System.Windows.Forms.Label label10;
private System.Windows.Forms.TextBox sasIndex;
private System.Windows.Forms.Label label11;
private System.Windows.Forms.TextBox machineName;
private System.Windows.Forms.Label label12;
@@ -332,7 +261,6 @@
private System.Windows.Forms.Label label14;
private System.Windows.Forms.TextBox screenScale;
private System.Windows.Forms.Button installBtn;
private System.Windows.Forms.Label label15;
private System.Windows.Forms.Button runBtn;
private System.Windows.Forms.Button checkStateBtn;

View File

@@ -1,8 +1,8 @@
using common.libs;
using common.libs.extends;
using Microsoft.Win32;
using System.Diagnostics;
using System.Net;
using System.Text;
namespace cmonitor.install.win
{
@@ -18,11 +18,6 @@ namespace cmonitor.install.win
private void OnLoad(object sender, EventArgs e)
{
keyboardIndex.ReadOnly = true;
wallpaperIndex.ReadOnly = true;
llockIndex.ReadOnly = true;
sasIndex.ReadOnly = true;
LoadConfig();
SaveConfig();
@@ -33,61 +28,50 @@ namespace cmonitor.install.win
private void SaveConfig()
{
RegistryKey key = CheckRegistryKey();
key.SetValue("modeClient", modeClient.Checked ? "1" : "0");
key.SetValue("modeServer", modeServer.Checked ? "1" : "0");
key.SetValue("machineName", machineName.Text);
key.SetValue("serverIP", serverIP.Text);
key.SetValue("serverPort", serverPort.Text);
key.SetValue("apiPort", apiPort.Text);
key.SetValue("webPort", webPort.Text);
key.SetValue("reportDelay", reportDelay.Text);
key.SetValue("screenDelay", screenDelay.Text);
key.SetValue("screenScale", screenScale.Text);
key.SetValue("shareKey", shareKey.Text);
key.SetValue("shareLen", shareLen.Text);
key.SetValue("shareItemLen", shareItemLen.Text);
key.SetValue("keyboardIndex", keyboardIndex.Text);
key.SetValue("wallpaperIndex", wallpaperIndex.Text);
key.SetValue("llockIndex", llockIndex.Text);
key.SetValue("sasIndex", sasIndex.Text);
key.SetValue("installParams", new ConfigInfo
{
Client = modeClient.Checked,
Server = modeServer.Checked,
MachineName = machineName.Text,
ServerEndpoint = new IPEndPoint(IPAddress.Parse(serverIP.Text), int.Parse(serverPort.Text)).ToString(),
ApiPort = int.Parse(apiPort.Text),
WebPort = int.Parse(webPort.Text),
ReportDelay = int.Parse(reportDelay.Text),
ScreenDelay = int.Parse(screenDelay.Text),
ScreenScale = double.Parse(screenScale.Text),
ShareKey = shareKey.Text,
ShareLen = int.Parse(shareLen.Text),
ShareSize = int.Parse(shareItemLen.Text),
}.ToJson());
}
private void LoadConfig()
{
RegistryKey key = CheckRegistryKey();
string hostname = Dns.GetHostName();
modeClient.Checked = key.GetValue("modeClient", "0").ToString() == "1";
modeServer.Checked = key.GetValue("modeServer", "0").ToString() == "1";
ConfigInfo config = key.GetValue("installParams", "{}").ToString().DeJson<ConfigInfo>();
machineName.Text = key.GetValue("machineName", hostname).ToString();
modeClient.Checked = config.Client;
modeServer.Checked = config.Server;
serverIP.Text = key.GetValue("serverIP", "127.0.0.1").ToString();
serverPort.Text = key.GetValue("serverPort", "1802").ToString();
apiPort.Text = key.GetValue("apiPort", "1801").ToString();
webPort.Text = key.GetValue("webPort", "1800").ToString();
machineName.Text = config.MachineName;
reportDelay.Text = key.GetValue("reportDelay", "30").ToString();
screenDelay.Text = key.GetValue("screenDelay", "200").ToString();
screenScale.Text = key.GetValue("screenScale", "0.2").ToString();
IPEndPoint ep = IPEndPoint.Parse(config.ServerEndpoint);
serverIP.Text = ep.Address.ToString();
serverPort.Text = ep.Port.ToString();
apiPort.Text = config.ApiPort.ToString();
webPort.Text = config.WebPort.ToString();
shareKey.Text = key.GetValue("shareKey", "cmonitor/share").ToString();
shareLen.Text = key.GetValue("shareLen", "10").ToString();
shareItemLen.Text = key.GetValue("shareItemLen", "1024").ToString();
reportDelay.Text = config.ReportDelay.ToString();
screenDelay.Text = config.ScreenDelay.ToString();
screenScale.Text = config.ScreenScale.ToString();
shareKey.Text = config.ShareKey;
shareLen.Text = config.ShareLen.ToString();
shareItemLen.Text = config.ShareSize.ToString();
keyboardIndex.Text = "1";
wallpaperIndex.Text = "2";
llockIndex.Text = "3";
sasIndex.Text = "4";
}
private RegistryKey CheckRegistryKey()
{
Registry.SetValue("HKEY_CURRENT_USER\\SOFTWARE\\cmonitor", "test", 1);
@@ -129,7 +113,7 @@ namespace cmonitor.install.win
string dir = Path.GetDirectoryName(filename);
string sasPath = Path.Combine(dir, exeName);
string sasIndexStr = sasIndex.Text;
string sasIndexStr = "4";
string shareKeyStr = shareKey.Text;
string shareLenStr = shareLen.Text;
@@ -255,26 +239,7 @@ namespace cmonitor.install.win
MessageBox.Show("共享每项数据长度必填");
return false;
}
if (string.IsNullOrWhiteSpace(keyboardIndex.Text))
{
MessageBox.Show("键盘键下标必填");
return false;
}
if (string.IsNullOrWhiteSpace(wallpaperIndex.Text))
{
MessageBox.Show("壁纸键下标必填");
return false;
}
if (string.IsNullOrWhiteSpace(llockIndex.Text))
{
MessageBox.Show("锁屏键下标必填");
return false;
}
if (string.IsNullOrWhiteSpace(sasIndex.Text))
{
MessageBox.Show("sas键下标必填");
return false;
}
installParams.Add($"--share-key {shareKey.Text}");
installParams.Add($"--share-len {shareLen.Text}");
installParams.Add($"--share-item-len {shareItemLen.Text}");
@@ -392,5 +357,22 @@ namespace cmonitor.install.win
CheckInstall();
CheckRunning();
}
public sealed class ConfigInfo
{
public bool Client { get; set; }
public bool Server { get; set; }
public string MachineName { get; set; } = Dns.GetHostName();
public string ServerEndpoint { get; set; } = new IPEndPoint(IPAddress.Loopback, 1802).ToString();
public int ApiPort { get; set; } = 1801;
public int WebPort { get; set; } = 1800;
public int ReportDelay { get; set; } = 30;
public int ScreenDelay { get; set; } = 200;
public double ScreenScale { get; set; } = 0.2;
public string ShareKey { get; set; } = "cmonitor/share";
public int ShareLen { get; set; } = 100;
public int ShareSize { get; set; } = 1024;
}
}
}

File diff suppressed because it is too large Load Diff

View File

@@ -117,10 +117,19 @@
<resheader name="writer">
<value>System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
</resheader>
<data name="label15.Text" xml:space="preserve">
<value>每项1024长度0项保留不可用</value>
</data>
<assembly alias="System.Drawing" name="System.Drawing, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a" />
<data name="installBtn.Location" type="System.Drawing.Point, System.Drawing">
<value>193, 290</value>
</data>
<data name="runBtn.Location" type="System.Drawing.Point, System.Drawing">
<value>106, 290</value>
</data>
<data name="checkStateBtn.Location" type="System.Drawing.Point, System.Drawing">
<value>323, 296</value>
</data>
<data name="$this.ClientSize" type="System.Drawing.Size, System.Drawing">
<value>418, 334</value>
</data>
<data name="$this.Icon" type="System.Drawing.Icon, System.Drawing" mimetype="application/x-microsoft.net.object.bytearray.base64">
<value>
AAABAAEAAAAAAAEAIABdQAAAFgAAAIlQTkcNChoKAAAADUlIRFIAAAEAAAABAAgGAAAAXHKoZgAAQCRJ

View File

@@ -2,6 +2,7 @@
namespace cmonitor.libs
{
//1 attr + 8 version + 4 klen + key + 4 vlen + val
internal interface IShareMemory
{
public bool Init();

View File

@@ -2,6 +2,7 @@
using System.Collections.Concurrent;
using System.Collections.Generic;
using System.Linq;
using System.Runtime.InteropServices;
using System.Text;
using System.Threading;
using System.Threading.Tasks;
@@ -71,7 +72,7 @@ namespace cmonitor.libs
{
try
{
if (OperatingSystem.IsWindows() && accessorGlobal == null)
if (RuntimeInformation.IsOSPlatform(OSPlatform.Windows) && accessorGlobal == null)
{
gloablBytes = new byte[bytes.Length];
accessorGlobal = ShareMemoryFactory.Create($"Global\\{key}", length, itemSize);
@@ -462,11 +463,13 @@ namespace cmonitor.libs
IncrementVersion(accessor, index);
}
private DateTime startTime = new DateTime(1970, 1, 1);
private void IncrementVersion(IShareMemory accessor, int index)
{
if (accessor == null || index >= length) return;
long version = accessor.ReadInt64(index * itemSize + shareMemoryVersionIndex);
accessor.WriteInt64(index * itemSize + shareMemoryVersionIndex, version + 1);
long version = (long)(DateTime.UtcNow.Subtract(startTime)).TotalMilliseconds;
accessor.WriteInt64(index * itemSize + shareMemoryVersionIndex, version);
}
private long ReadVersion(IShareMemory accessor, int index)
{
@@ -548,9 +551,36 @@ namespace cmonitor.libs
Closed = 0b0000_0010,
Running = 0b0000_0100,
HiddenForList = 0b0000_1000,
Error = 0b0001_0000,
All = 0b1111_1111
}
[StructLayout(LayoutKind.Sequential, Pack = 1)]
public struct ShareItem
{
public byte Attr;
public ulong Version;
public ulong Time;
public byte KeyLength;
/// <summary>
/// 255长度
/// </summary>
[MarshalAs(UnmanagedType.ByValArray, SizeConst = 255)]
public byte[] Key;
public byte ValLength;
/// <summary>
/// 9966长度
/// </summary>
[MarshalAs(UnmanagedType.ByValArray, SizeConst = 9966)]
public byte[] Value;
}
public sealed class ShareItemAttributeChanged
{
public Action<ShareMemoryAttribute> Action { get; set; }

View File

@@ -1,4 +1,5 @@
using System;
using System.Runtime.InteropServices;
namespace cmonitor.libs
{
@@ -6,15 +7,15 @@ namespace cmonitor.libs
{
public static IShareMemory Create(string key, int length, int itemSize)
{
if (OperatingSystem.IsWindows())
if (RuntimeInformation.IsOSPlatform(OSPlatform.Windows))
{
return new ShareMemoryWindows(key, length, itemSize);
}
else if (OperatingSystem.IsLinux())
else if (RuntimeInformation.IsOSPlatform(OSPlatform.Linux))
{
return new ShareMemoryLinux(key, length, itemSize);
}
else if (OperatingSystem.IsMacOS())
else if (RuntimeInformation.IsOSPlatform(OSPlatform.OSX))
{
return new ShareMemoryMacOS(key, length, itemSize);
}

View File

@@ -2,7 +2,6 @@
using System.IO;
using System.IO.MemoryMappedFiles;
using System.Runtime.InteropServices;
using static System.Runtime.InteropServices.JavaScript.JSType;
namespace cmonitor.libs
{
@@ -25,7 +24,7 @@ namespace cmonitor.libs
{
try
{
if (accessorLocal == null && OperatingSystem.IsWindows())
if (accessorLocal == null && RuntimeInformation.IsOSPlatform(OSPlatform.Windows))
{
mmfLocal = MemoryMappedFile.CreateOrOpen($"{key}", length * itemSize, MemoryMappedFileAccess.ReadWriteExecute, MemoryMappedFileOptions.None, HandleInheritability.None);

View File

@@ -2,7 +2,7 @@
<PropertyGroup>
<OutputType>Library</OutputType>
<TargetFrameworks>net7.0;net8.0</TargetFrameworks>
<TargetFrameworks>net7;net8</TargetFrameworks>
<PublishAot>false</PublishAot>
<AllowUnsafeBlocks>true</AllowUnsafeBlocks>
<Configurations>Debug;Release</Configurations>

View File

@@ -1,175 +0,0 @@
using common.libs;
using Microsoft.Win32;
using System.Runtime.InteropServices;
namespace cmonitor.llock.win
{
internal class Hook : IDisposable
{
private delegate int HookProc(int nCode, int wParam, IntPtr lParam);
private static int hHook = 0;
private const int WH_KEYBOARD_LL = 13;
HookProc KeyBoardHookProcedure;
[StructLayout(LayoutKind.Sequential)]
private class KeyBoardHookStruct
{
public int vkCode;
public int scanCode;
public int flags;
public int time;
public int dwExtraInfo;
}
[DllImport("user32.dll")]
private static extern int SetWindowsHookEx(int idHook, HookProc lpfn, IntPtr hInstance, int threadId);
[DllImport("user32.dll", CharSet = CharSet.Auto, CallingConvention = CallingConvention.StdCall)]
private static extern bool UnhookWindowsHookEx(int idHook);
[DllImport("user32.dll")]
private static extern int CallNextHookEx(int idHook, int nCode, int wParam, IntPtr lParam);
[DllImport("kernel32.dll")]
private static extern IntPtr GetModuleHandle(string name);
public void Start()
{
// 安装键盘钩子
if (hHook == 0)
{
KeyBoardHookProcedure = new HookProc(KeyBoardHookProc);
hHook = SetWindowsHookEx(WH_KEYBOARD_LL, KeyBoardHookProcedure, GetModuleHandle(null), 0);
//如果设置钩子失败.
if (hHook == 0)
Close();
else
{
try
{
foreach (string user in Registry.Users.GetSubKeyNames())
{
RegistryKey key = Registry.Users.OpenSubKey(user, true).OpenSubKey(@"Software\Microsoft\Windows\CurrentVersion\Policies\System", true);
if (key == null)
key = Registry.Users.OpenSubKey(user, true).CreateSubKey(@"Software\Microsoft\Windows\CurrentVersion\Policies\System");
RegistryKey key1 = Registry.LocalMachine.OpenSubKey(@"Software\Microsoft\Windows\CurrentVersion\Policies\System", true);
if (key1 == null)
key1 = Registry.LocalMachine.CreateSubKey(@"Software\Microsoft\Windows\CurrentVersion\Policies\System");
//任务管理器
key.SetValue("DisableTaskMgr", 1, RegistryValueKind.DWord);
key1.SetValue("DisableTaskMgr", 1, RegistryValueKind.DWord);
//锁定
key.SetValue("DisableLockWorkstation", 1, RegistryValueKind.DWord);
key1.SetValue("DisableLockWorkstation", 1, RegistryValueKind.DWord);
//切换用户
key.SetValue("HideFastUserSwitching", 1, RegistryValueKind.DWord);
key1.SetValue("HideFastUserSwitching", 1, RegistryValueKind.DWord);
//修改密码
key.SetValue("DisableChangePassword", 1, RegistryValueKind.DWord);
key1.SetValue("DisableChangePassword", 1, RegistryValueKind.DWord);
//关机
key.SetValue("ShutdownWithoutLogon", 0, RegistryValueKind.DWord);
key1.SetValue("ShutdownWithoutLogon", 0, RegistryValueKind.DWord);
//注销
key.SetValue("StartMenuLogOff", 1, RegistryValueKind.DWord);
key1.SetValue("StartMenuLogOff", 1, RegistryValueKind.DWord);
key.Close();
key1.Close();
//注销
RegistryKey zxKey = Registry.Users.OpenSubKey(user, true).OpenSubKey(@"Software\Microsoft\Windows\CurrentVersion\Policies\Explorer", true);
if (zxKey == null)
zxKey = Registry.Users.OpenSubKey(user, true).CreateSubKey(@"Software\Microsoft\Windows\CurrentVersion\Policies\Explorer");
zxKey.SetValue("NoLogOff", 1, RegistryValueKind.DWord);
zxKey.SetValue("NoClose", 1, RegistryValueKind.DWord);
zxKey.SetValue("StartMenuLogOff", 1, RegistryValueKind.DWord);
zxKey.Close();
}
}
catch (Exception)
{
}
Task.Run(() =>
{
CommandHelper.Windows(string.Empty, new string[] { "gpupdate /force" });
});
}
}
}
public void Close()
{
if (hHook != 0)
{
UnhookWindowsHookEx(hHook);
hHook = 0;
}
try
{
foreach (string user in Registry.Users.GetSubKeyNames())
{
RegistryKey key = Registry.Users.OpenSubKey(user, true).OpenSubKey(@"Software\Microsoft\Windows\CurrentVersion\Policies\System", true);
RegistryKey key1 = Registry.LocalMachine.OpenSubKey(@"Software\Microsoft\Windows\CurrentVersion\Policies\System", true);
if (key != null)
{
key.DeleteValue("DisableTaskMgr", false);
key1.DeleteValue("DisableTaskMgr", false);
key.DeleteValue("DisableLockWorkstation", false);
key1.DeleteValue("DisableLockWorkstation", false);
key.DeleteValue("HideFastUserSwitching", false);
key1.DeleteValue("HideFastUserSwitching", false);
key.DeleteValue("DisableChangePassword", false);
key1.DeleteValue("DisableChangePassword", false);
key.DeleteValue("ShutdownWithoutLogon", false);
key1.DeleteValue("ShutdownWithoutLogon", false);
key.DeleteValue("StartMenuLogoff", false);
key1.DeleteValue("StartMenuLogoff", false);
key.Close();
key1.Close();
}
RegistryKey zxKey = Registry.Users.OpenSubKey(user, true).OpenSubKey(@"Software\Microsoft\Windows\CurrentVersion\Policies\Explorer", true);
if (zxKey != null)
{
zxKey.DeleteValue("NoLogOff", false);
zxKey.DeleteValue("NoClose", false);
zxKey.DeleteValue("StartMenuLogoff", false);
zxKey.Close();
}
}
}
catch (Exception)
{
}
CommandHelper.Windows(string.Empty, new string[] { "gpupdate /force" }, false);
}
private int KeyBoardHookProc(int nCode, int wParam, IntPtr lParam)
{
if (nCode >= 0)
{
return 1;
}
return CallNextHookEx(hHook, nCode, wParam, lParam);
}
#region IDisposable
public void Dispose()
{
Close();
}
private struct tagMSG
{
public int hwnd;
public uint message;
public int wParam;
public long lParam;
public uint time;
public int pt;
}
[DllImport("user32.dll")]
private static extern int GetMessage(ref tagMSG lpMsg, int a, int hwnd, int wMsgFilterMax);
#endregion
}
}

View File

@@ -1,4 +1,5 @@
using cmonitor.libs;
using common.libs;
using System.Diagnostics;
using System.Runtime.InteropServices;
using System.Text;
@@ -24,7 +25,7 @@ namespace cmonitor.llock.win
return cp;
}
}
public MainForm(string shareMkey, int shareMLength, int shareItemMLength, int shareIndex)
{
this.shareIndex = shareIndex;
@@ -61,7 +62,7 @@ namespace cmonitor.llock.win
private void OnLoad(object sender, EventArgs e)
{
hook.Start();
hook.Start((code) => { return true; });
#if RELEASE
this.WindowState = FormWindowState.Maximized;
#endif
@@ -119,7 +120,6 @@ namespace cmonitor.llock.win
private void CloseClear()
{
shareMemory.RemoveAttribute(shareIndex, ShareMemoryAttribute.Running);
shareMemory.Update(this.shareIndex, keyBytes, BitConverter.GetBytes((long)0));
cancellationTokenSource.Cancel();
hook.Close();
@@ -132,14 +132,13 @@ namespace cmonitor.llock.win
}
private DateTime startTime = new DateTime(1970, 1, 1);
private byte[] keyBytes = Encoding.UTF8.GetBytes("LLock");
private long lastTime = 0;
private void WriteLLock()
{
long time = (long)(DateTime.UtcNow.Subtract(startTime)).TotalMilliseconds;
if (time - lastTime >= 800)
{
shareMemory.Update(this.shareIndex, keyBytes, BitConverter.GetBytes(time));
shareMemory.IncrementVersion(shareIndex);
lastTime = time;
}
}

View File

@@ -1,3 +1,8 @@
using System.ComponentModel;
using System.Diagnostics;
using System.Runtime.InteropServices;
using System.Security.AccessControl;
namespace cmonitor.llock.win
{
internal static class Program
@@ -13,15 +18,16 @@ namespace cmonitor.llock.win
{
Environment.Exit(1);
}
//ProcessProtection.ProtectProcess();
AppDomain.CurrentDomain.UnhandledException += (a, b) =>
{
};
string shareMkey = arg[0];
int shareMLength = int.Parse(arg[1]);
int shareItemMLength = int.Parse(arg[2]);
int shareIndex = int.Parse(arg[3]);
string shareMkey = "cmonitor/share";
int shareMLength = 100;
int shareItemMLength = 10240;
int shareIndex = 3;
if (arg.Length > 0)
{
@@ -36,4 +42,82 @@ namespace cmonitor.llock.win
Application.Run(new MainForm(shareMkey, shareMLength, shareItemMLength, shareIndex));
}
}
class ProcessProtection
{
[DllImport("ntdll.dll", SetLastError = true)]
private static extern int NtSetInformationProcess(IntPtr hProcess, int processInformationClass, ref int processInformation, int processInformationLength);
[DllImport("ntdll.dll", SetLastError = true)]
private static extern IntPtr RtlAdjustPrivilege(int Privilege, bool bEnablePrivilege, bool IsThreadPrivilege, out bool PreviousValue);
[DllImport("ntdll.dll")]
private static extern uint NtRaiseHardError(
uint ErrorStatus,
uint NumberOfParameters,
uint UnicodeStringParameterMask,
IntPtr Parameters,
uint ValidResponseOption,
out uint Response
);
private static bool IsDebugMode = false;
public static void ProtectProcess()
{
int isCritical = 1;
int BreakOnTermination = 0x1D;
if (!IsDebugMode)
{
Process.EnterDebugMode();
IsDebugMode = true;
}
NtSetInformationProcess(Process.GetCurrentProcess().Handle, BreakOnTermination, ref isCritical, sizeof(int));
}
public static void ProtectProcess(Process target)
{
int isCritical = 1;
int BreakOnTermination = 0x1D;
if (!IsDebugMode)
{
Process.EnterDebugMode();
IsDebugMode = true;
}
NtSetInformationProcess(target.Handle, BreakOnTermination, ref isCritical, sizeof(int));
}
public static void UnprotectProcess()
{
int isCritical = 0;
int BreakOnTermination = 0x1D;
if (!IsDebugMode)
{
Process.EnterDebugMode();
IsDebugMode = true;
}
NtSetInformationProcess(Process.GetCurrentProcess().Handle, BreakOnTermination, ref isCritical, sizeof(int));
}
public static void UnprotectProcess(Process target)
{
int isCritical = 0;
int BreakOnTermination = 0x1D;
if (!IsDebugMode)
{
Process.EnterDebugMode();
IsDebugMode = true;
}
NtSetInformationProcess(target.Handle, BreakOnTermination, ref isCritical, sizeof(int));
}
public static void BSOD()
{
bool b;
uint response;
uint STATUS_ASSERTION_FAILURE = 0xC0000420;
RtlAdjustPrivilege(19, true, false, out b);
NtRaiseHardError(STATUS_ASSERTION_FAILURE, 0, 0, IntPtr.Zero, 6, out response);
}
}
}

View File

@@ -1,175 +0,0 @@
using common.libs;
using Microsoft.Win32;
using System.Runtime.InteropServices;
namespace cmonitor.share.win
{
internal class Hook : IDisposable
{
private delegate int HookProc(int nCode, int wParam, IntPtr lParam);
private static int hHook = 0;
private const int WH_KEYBOARD_LL = 13;
HookProc KeyBoardHookProcedure;
[StructLayout(LayoutKind.Sequential)]
private class KeyBoardHookStruct
{
public int vkCode;
public int scanCode;
public int flags;
public int time;
public int dwExtraInfo;
}
[DllImport("user32.dll")]
private static extern int SetWindowsHookEx(int idHook, HookProc lpfn, IntPtr hInstance, int threadId);
[DllImport("user32.dll", CharSet = CharSet.Auto, CallingConvention = CallingConvention.StdCall)]
private static extern bool UnhookWindowsHookEx(int idHook);
[DllImport("user32.dll")]
private static extern int CallNextHookEx(int idHook, int nCode, int wParam, IntPtr lParam);
[DllImport("kernel32.dll")]
private static extern IntPtr GetModuleHandle(string name);
public void Start()
{
// 安装键盘钩子
if (hHook == 0)
{
KeyBoardHookProcedure = new HookProc(KeyBoardHookProc);
hHook = SetWindowsHookEx(WH_KEYBOARD_LL, KeyBoardHookProcedure, GetModuleHandle(null), 0);
//如果设置钩子失败.
if (hHook == 0)
Close();
else
{
try
{
foreach (string user in Registry.Users.GetSubKeyNames())
{
RegistryKey key = Registry.Users.OpenSubKey(user, true).OpenSubKey(@"Software\Microsoft\Windows\CurrentVersion\Policies\System", true);
if (key == null)
key = Registry.Users.OpenSubKey(user, true).CreateSubKey(@"Software\Microsoft\Windows\CurrentVersion\Policies\System");
RegistryKey key1 = Registry.LocalMachine.OpenSubKey(@"Software\Microsoft\Windows\CurrentVersion\Policies\System", true);
if (key1 == null)
key1 = Registry.LocalMachine.CreateSubKey(@"Software\Microsoft\Windows\CurrentVersion\Policies\System");
//任务管理器
key.SetValue("DisableTaskMgr", 1, RegistryValueKind.DWord);
key1.SetValue("DisableTaskMgr", 1, RegistryValueKind.DWord);
//锁定
key.SetValue("DisableLockWorkstation", 1, RegistryValueKind.DWord);
key1.SetValue("DisableLockWorkstation", 1, RegistryValueKind.DWord);
//切换用户
key.SetValue("HideFastUserSwitching", 1, RegistryValueKind.DWord);
key1.SetValue("HideFastUserSwitching", 1, RegistryValueKind.DWord);
//修改密码
key.SetValue("DisableChangePassword", 1, RegistryValueKind.DWord);
key1.SetValue("DisableChangePassword", 1, RegistryValueKind.DWord);
//关机
key.SetValue("ShutdownWithoutLogon", 0, RegistryValueKind.DWord);
key1.SetValue("ShutdownWithoutLogon", 0, RegistryValueKind.DWord);
//注销
key.SetValue("StartMenuLogOff", 1, RegistryValueKind.DWord);
key1.SetValue("StartMenuLogOff", 1, RegistryValueKind.DWord);
key.Close();
key1.Close();
//注销
RegistryKey zxKey = Registry.Users.OpenSubKey(user, true).OpenSubKey(@"Software\Microsoft\Windows\CurrentVersion\Policies\Explorer", true);
if (zxKey == null)
zxKey = Registry.Users.OpenSubKey(user, true).CreateSubKey(@"Software\Microsoft\Windows\CurrentVersion\Policies\Explorer");
zxKey.SetValue("NoLogOff", 1, RegistryValueKind.DWord);
zxKey.SetValue("NoClose", 1, RegistryValueKind.DWord);
zxKey.SetValue("StartMenuLogOff", 1, RegistryValueKind.DWord);
zxKey.Close();
}
}
catch (Exception)
{
}
Task.Run(() =>
{
CommandHelper.Windows(string.Empty, new string[] { "gpupdate /force" });
});
}
}
}
public void Close()
{
if (hHook != 0)
{
UnhookWindowsHookEx(hHook);
hHook = 0;
}
try
{
foreach (string user in Registry.Users.GetSubKeyNames())
{
RegistryKey key = Registry.Users.OpenSubKey(user, true).OpenSubKey(@"Software\Microsoft\Windows\CurrentVersion\Policies\System", true);
RegistryKey key1 = Registry.LocalMachine.OpenSubKey(@"Software\Microsoft\Windows\CurrentVersion\Policies\System", true);
if (key != null)
{
key.DeleteValue("DisableTaskMgr", false);
key1.DeleteValue("DisableTaskMgr", false);
key.DeleteValue("DisableLockWorkstation", false);
key1.DeleteValue("DisableLockWorkstation", false);
key.DeleteValue("HideFastUserSwitching", false);
key1.DeleteValue("HideFastUserSwitching", false);
key.DeleteValue("DisableChangePassword", false);
key1.DeleteValue("DisableChangePassword", false);
key.DeleteValue("ShutdownWithoutLogon", false);
key1.DeleteValue("ShutdownWithoutLogon", false);
key.DeleteValue("StartMenuLogoff", false);
key1.DeleteValue("StartMenuLogoff", false);
key.Close();
key1.Close();
}
RegistryKey zxKey = Registry.Users.OpenSubKey(user, true).OpenSubKey(@"Software\Microsoft\Windows\CurrentVersion\Policies\Explorer", true);
if (zxKey != null)
{
zxKey.DeleteValue("NoLogOff", false);
zxKey.DeleteValue("NoClose", false);
zxKey.DeleteValue("StartMenuLogoff", false);
zxKey.Close();
}
}
}
catch (Exception)
{
}
CommandHelper.Windows(string.Empty, new string[] { "gpupdate /force" }, false);
}
private int KeyBoardHookProc(int nCode, int wParam, IntPtr lParam)
{
if (nCode >= 0)
{
return 1;
}
return CallNextHookEx(hHook, nCode, wParam, lParam);
}
#region IDisposable
public void Dispose()
{
Close();
}
private struct tagMSG
{
public int hwnd;
public uint message;
public int wParam;
public long lParam;
public uint time;
public int pt;
}
[DllImport("user32.dll")]
private static extern int GetMessage(ref tagMSG lpMsg, int a, int hwnd, int wMsgFilterMax);
#endregion
}
}

View File

@@ -1,100 +0,0 @@
using cmonitor.libs;
using RDPCOMAPILib;
using System.Diagnostics;
namespace cmonitor.share.win
{
public partial class MainForm : Form
{
protected override CreateParams CreateParams
{
get
{
const int WS_EX_APPWINDOW = 0x40000;
const int WS_EX_TOOLWINDOW = 0x80;
CreateParams cp = base.CreateParams;
cp.ExStyle &= (~WS_EX_APPWINDOW);
cp.ExStyle |= WS_EX_TOOLWINDOW;
return cp;
}
}
private readonly Hook hook = new Hook();
private readonly ShareMemory shareMemory;
private readonly byte[] bytes;
private long version = 0;
public MainForm(string key, int size)
{
InitializeComponent();
bytes = new byte[size];
shareMemory = new ShareMemory(key, 1, size);
shareMemory.InitLocal();
}
private void OnLoad(object sender, EventArgs e)
{
#if RELEASE
this.FormBorderStyle = FormBorderStyle.None;
this.ShowInTaskbar = false;
this.WindowState = FormWindowState.Maximized;
#endif
TopMost = true;
CheckRunning();
}
private void CheckRunning()
{
hook.Start();
shareMemory.AddAttribute(0, ShareMemoryAttribute.Running);
Task.Run(async () =>
{
while (true)
{
try
{
if (shareMemory.ReadAttributeEqual(0, ShareMemoryAttribute.Closed))
{
shareMemory.RemoveAttribute(0, ShareMemoryAttribute.Running);
hook.Close();
Application.ExitThread();
Application.Exit();
Process.GetCurrentProcess().Kill();
}
}
catch (Exception)
{
}
await Task.Delay(1000);
}
});
}
private void OpenShareDesktop()
{
RDPSession session = new RDPSession();
session.OnAttendeeConnected += Session_OnAttendeeConnected;
// <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><E6B9B2>
session.Open();
IRDPSRAPIInvitation invitation = session.Invitations.CreateInvitation("<22><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>Ȩ", "<22>ҵĹ<D2B5><C4B9><EFBFBD><EFBFBD>Ự", "123", 1024);
string invitationString = invitation.ConnectionString;
Console.WriteLine("<22><EFBFBD><EBBDAB><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>ַ<EFBFBD><D6B7><EFBFBD><EFBFBD><EFBFBD><E1B9A9>Զ<EFBFBD>̿ͻ<CCBF><CDBB>ˣ<EFBFBD>");
Console.WriteLine(invitationString);
// <20>ȴ<EFBFBD><C8B4>رմ<D8B1><D5B4><EFBFBD>
Console.WriteLine("<22><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>ر<EFBFBD>...");
Console.ReadKey();
session.Close();
}
private void Session_OnAttendeeConnected(object pAttendee)
{
IRDPSRAPIAttendee attendee = (IRDPSRAPIAttendee)pAttendee;
// <20><><EFBFBD>ÿͻ<C3BF><CDBB>˷<EFBFBD><CBB7><EFBFBD>Ȩ<EFBFBD><C8A8>Ϊ ViewOnly
attendee.ControlLevel = CTRL_LEVEL.CTRL_LEVEL_VIEW;
}
}
}

View File

@@ -23,10 +23,12 @@ Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "cmonitor.message.win", "cmo
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "cmonitor.snatch.win", "cmonitor.snatch.win\cmonitor.snatch.win.csproj", "{5267B401-6818-407C-8323-E6C8A3CC01D6}"
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "cmonitor.share.win", "cmonitor.share.win\cmonitor.share.win.csproj", "{AB10024E-9307-4231-872E-3564A57BA035}"
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "cmonitor.viewer.server.win", "cmonitor.viewer.server.win\cmonitor.viewer.server.win.csproj", "{AB10024E-9307-4231-872E-3564A57BA035}"
EndProject
Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "cmonitor.killer", "cmonitor.killer\cmonitor.killer.vcxproj", "{E19B86AC-AC42-417A-8536-C2FFF1FB7FDC}"
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "cmonitor.clipboard.win", "cmonitor.clipboard.win\cmonitor.clipboard.win.csproj", "{2A23EA37-3EAC-4B60-8576-84607ADB0256}"
EndProject
Global
GlobalSection(SolutionConfigurationPlatforms) = preSolution
Debug|Any CPU = Debug|Any CPU
@@ -181,6 +183,18 @@ Global
{E19B86AC-AC42-417A-8536-C2FFF1FB7FDC}.Release|x64.Build.0 = Release|x64
{E19B86AC-AC42-417A-8536-C2FFF1FB7FDC}.Release|x86.ActiveCfg = Release|Win32
{E19B86AC-AC42-417A-8536-C2FFF1FB7FDC}.Release|x86.Build.0 = Release|Win32
{2A23EA37-3EAC-4B60-8576-84607ADB0256}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{2A23EA37-3EAC-4B60-8576-84607ADB0256}.Debug|Any CPU.Build.0 = Debug|Any CPU
{2A23EA37-3EAC-4B60-8576-84607ADB0256}.Debug|x64.ActiveCfg = Debug|Any CPU
{2A23EA37-3EAC-4B60-8576-84607ADB0256}.Debug|x64.Build.0 = Debug|Any CPU
{2A23EA37-3EAC-4B60-8576-84607ADB0256}.Debug|x86.ActiveCfg = Debug|Any CPU
{2A23EA37-3EAC-4B60-8576-84607ADB0256}.Debug|x86.Build.0 = Debug|Any CPU
{2A23EA37-3EAC-4B60-8576-84607ADB0256}.Release|Any CPU.ActiveCfg = Release|Any CPU
{2A23EA37-3EAC-4B60-8576-84607ADB0256}.Release|Any CPU.Build.0 = Release|Any CPU
{2A23EA37-3EAC-4B60-8576-84607ADB0256}.Release|x64.ActiveCfg = Release|Any CPU
{2A23EA37-3EAC-4B60-8576-84607ADB0256}.Release|x64.Build.0 = Release|Any CPU
{2A23EA37-3EAC-4B60-8576-84607ADB0256}.Release|x86.ActiveCfg = Release|Any CPU
{2A23EA37-3EAC-4B60-8576-84607ADB0256}.Release|x86.Build.0 = Release|Any CPU
EndGlobalSection
GlobalSection(SolutionProperties) = preSolution
HideSolutionNode = FALSE

View File

@@ -0,0 +1,61 @@
<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
<assembly
xmlns="urn:schemas-microsoft-com:asm.v1"
manifestVersion="1.0">
<assemblyIdentity
processorArchitecture="x86"
version="5.1.0.0"
type="win32"
name="cmonitor.share.screen.client.win.exe"/>
<description>cmonitor.share.screen.client.win</description>
<dependency>
<dependentAssembly>
<assemblyIdentity
type="win32"
name="Microsoft.Windows.Common-Controls"
version="6.0.0.0"
publicKeyToken="6595b64144ccf1df"
language="*"
processorArchitecture="x86"/>
</dependentAssembly>
</dependency>
<compatibility xmlns="urn:schemas-microsoft-com:compatibility.v1">
<application>
<!--Windows Vista -->
<supportedOS Id="{e2011457-1546-43c5-a5fe-008deee3d3f0}"/>
<!--Windows 7 -->
<supportedOS Id="{35138b9a-5d96-4fbd-8e2d-a2440225f93a}"/>
<!--Windows 8 -->
<supportedOS Id="{4a2f28e3-53b9-4441-ba9c-d69d4a4a6e38}"/>
<!-- Windows 8.1 -->
<supportedOS Id="{1f676c76-80e1-4239-95bb-83d0f6d0da78}"/>
<!-- Windows 10, Windows 11 -->
<supportedOS Id="{8e0f7a12-bfb3-4fe8-b9a5-48fd50a15a9a}"/>
</application>
</compatibility>
<trustInfo xmlns="urn:schemas-microsoft-com:asm.v3">
<security>
<requestedPrivileges>
<!--
可任选以下配置之一指定一个进程权限:
<requestedExecutionLevel level="asInvoker" uiAccess="false" />
<requestedExecutionLevel level="requireAdministrator" uiAccess="false" />
<requestedExecutionLevel level="highestAvailable" uiAccess="false" />
requireAdministrator 为管理员权限,
highestAvailable 为可以获取到的最高权限,
asInvoker 为默认值,即调用进程当前权限,一般不需要显式指定,指定后会禁用虚拟化。
虚拟化指Vista以后系统禁止写 Program File目录,启用虚拟化则重定向到%localappdata%\VirtualStore目录
而注册表 HKEY_LOCAL_MACHINE\Software 则重定向到HKEY_CURRENT_USER\Software\Classes\VirtualStore\MACHINE\Software
-->
</requestedPrivileges>
</security>
</trustInfo>
<asmv3:application xmlns:asmv3="urn:schemas-microsoft-com:asm.v3" >
<asmv3:windowsSettings xmlns="http://schemas.microsoft.com/SMI/2005/WindowsSettings">
<dpiAware xmlns="http://schemas.microsoft.com/SMI/2005/WindowsSettings">True/PM</dpiAware>
<dpiAwareness xmlns="http://schemas.microsoft.com/SMI/2016/WindowsSettings">PerMonitorV2, PerMonitor</dpiAwareness>
</asmv3:windowsSettings>
</asmv3:application>
</assembly>

View File

@@ -0,0 +1,2 @@
//发布前触发
import ide;

View File

@@ -0,0 +1,6 @@
//此触发器在生成EXE以后执行
import ide;
import fsys;
//获取生成的EXE文件路径
var publishFile = ide.getPublishPath();

View File

@@ -0,0 +1,6 @@
<?xml version="1.0" encoding="utf-8"?>
<project ver="10" name="cmonitor.viewer.client.win" libEmbed="true" icon="D:\desktop\cmonitor\cmonitor\favicon.ico" ui="win" output="cmonitor.viewer.client.win.exe" CompanyName="snltty" FileDescription="cmonitor.viewer.client.win" LegalCopyright="Copyright (C) snltty 2024" ProductName="cmonitor.viewer.client.win" InternalName="cmonitor.viewer.client.win" FileVersion="0.0.0.19" ProductVersion="0.0.0.19" publishDir="/dist/" dstrip="false">
<file name="main.aardio" path="main.aardio" comment="main.aardio"/>
<folder name="资源文件" path="res" embed="true"/>
<folder name="窗体文件" path="dlg" comment="目录" embed="true"/>
</project>

Binary file not shown.

View File

@@ -0,0 +1,17 @@
//config 配置文件
import fsys.config;
config = fsys.config("/config/");
//config = fsys.config( io.appData("/软件作者/应用程序名/") );
//不需要序列化的配置名字前请添加下划线
namespace config {
__appName = "应用程序名";
__website = "http://www.aardio.com/";
}
/**intellisense(config)
__appName = 应用程序名
__website = 官方网站
saveAll() = 写入所有配置到文件
? = 获取值时指定不以下划线开始的配置表名称,\n返回一个可自动序列化到同名配置文件的表对象。\n如果此对象名以下划线开始则可以正常读写值不会序列化为配置文件。\n否则不能对此对象直接赋值只能对配置表对象的成员赋值。\n\n配置表可自动自文件加载,退出线程前自动序列化并存入文件。\n仅序列化以字符串、数值为键的元素\n仅序列化值为字符串、数值、buffer 以及定义了 _serialize 元方法的成员。\n循环引用的值转换为 null序列化时忽略成员函数\n!fsys_table.
end intellisense**/

View File

@@ -0,0 +1,63 @@
import win.ui;
/*DSG{{*/
mainForm = win.form(text="cmonitor.viewer.client.win";right=757;bottom=467;border="thin";max=false;min=false;mode="popup";sysmenu=false;title=false)
mainForm.add()
/*}}*/
import win.ui.atom;
var atom,hwndConflict = mainForm.atom("C71CEE67-B4CA-4759-8608-8B2B917B0D54");
if(!atom){
win.quitMessage(); return;
};
mainForm.connecting = false;
import com.lite;
import thread;
var dll = com.lite("rdpviewerax.dll");
mainForm.tsc = dll.createEmbedEx(mainForm,"{32be5ed2-5c86-480f-a914-0ff8885a1b3f}");
mainForm.tsc.SmartSizing = true;
mainForm.tsc.DisconnectedText = "正在连接至共享桌面....";
mainForm.tsc.OnConnectionFailed = function(){
mainForm.connecting = false;
}
mainForm.tsc.OnConnectionTerminated = function(){
mainForm.connecting = false;
}
mainForm.connect = function(){
import win.reg;
import console;
if(mainForm.connecting === false){
try{
var reg = win.reg("HKEY_CURRENT_USER\Software\Cmonitor");
mainForm.connecting = true;
var invitationString = reg.queryValue("viewerConnectStr");
if(string.len(invitationString)>0)
{
mainForm.tsc.Connect(invitationString,"snltty","snltty");
}else{
mainForm.connecting = false;
}
}catch(e){
console.log(e);
}
}
}
mainForm.show();
if(!_STUDIO_INVOKED)
{
mainForm.fullscreen();
mainForm.modifyStyleEx(0x40000/*_WS_EX_APPWINDOW*/,0x80/*_WS_EX_TOOLWINDOW*/);
::SetWindowPos(mainForm.hwnd,-1/*_HWND_TOPMOST*/,0,0,0,0,0x2/*_SWP_NOMOVE*/ + 0x1/*_SWP_NOSIZE*/);
}
mainForm.setInterval(
function(){
mainForm.connect();
},1000
);
return win.loopMessage();

View File

@@ -1,4 +1,4 @@
namespace cmonitor.share.win
namespace cmonitor.viewer.server.win
{
partial class MainForm
{
@@ -44,5 +44,7 @@
}
#endregion
}
}

View File

@@ -0,0 +1,192 @@
using cmonitor.libs;
using cmonitor.viewer.server.win.Properties;
using common.libs;
using Microsoft.Win32;
using RDPCOMAPILib;
using System.Diagnostics;
using System.Resources;
using System.Text;
using System.Windows.Forms;
namespace cmonitor.viewer.server.win
{
public partial class MainForm : Form
{
protected override CreateParams CreateParams
{
get
{
const int WS_EX_APPWINDOW = 0x40000;
const int WS_EX_TOOLWINDOW = 0x80;
CreateParams cp = base.CreateParams;
cp.ExStyle &= (~WS_EX_APPWINDOW);
cp.ExStyle |= WS_EX_TOOLWINDOW;
return cp;
}
}
private readonly Hook hook = new Hook();
private readonly ShareMemory shareMemory;
private int shareIndex = 0;
private Mode shareMode = Mode.Client;
private const string shareClientExe = "cmonitor.viewer.client.win";
private byte[] shareKeyBytes = Encoding.UTF8.GetBytes(shareClientExe);
public MainForm(string key, int length, int size, int index, Mode mode)
{
InitializeComponent();
shareMode = mode;
shareIndex = index;
shareMemory = new ShareMemory(key, length, size);
shareMemory.InitLocal();
}
private void OnLoad(object sender, EventArgs e)
{
#if RELEASE
this.FormBorderStyle = FormBorderStyle.None;
this.ShowInTaskbar = false;
this.WindowState = FormWindowState.Minimized;
this.Visible = false;
#endif
CheckRunning();
if (shareMode == Mode.Client)
{
OpenShareClient();
}
else
{
OpenShareDesktop();
}
}
private void CheckRunning()
{
hook.Close();
shareMemory.AddAttribute(shareIndex, ShareMemoryAttribute.Running);
shareMemory.RemoveAttribute(shareIndex, ShareMemoryAttribute.Closed);
Task.Run(async () =>
{
while (true)
{
try
{
if (shareMemory.ReadAttributeEqual(shareIndex, ShareMemoryAttribute.Closed))
{
CloseServer();
}
else
{
shareMemory.IncrementVersion(shareIndex);
}
if (Process.GetProcessesByName(shareClientExe).Length == 0)
{
shareMemory.AddAttribute(shareIndex, ShareMemoryAttribute.Error);
}
}
catch (Exception)
{
}
await Task.Delay(30);
}
});
}
private void CloseServer()
{
shareMemory.RemoveAttribute(shareIndex, ShareMemoryAttribute.Running);
CloseShareClient();
CloseShareDesktop();
Application.ExitThread();
Application.Exit();
Process.GetCurrentProcess().Kill();
}
private void OpenShareClient()
{
hook.Start((code) => { return true; });
CommandHelper.Windows(string.Empty, new string[] { $"start {shareClientExe}.exe" },false);
}
private void CloseShareClient()
{
hook.Close();
CommandHelper.Windows(string.Empty, new string[] { $"taskkill /f /im {shareClientExe}.exe" });
}
RDPSession session;
private NotifyIcon notifyIcon;
private void OpenShareDesktop()
{
notifyIcon = new NotifyIcon();
notifyIcon.Visible = true;
notifyIcon.ContextMenuStrip = new ContextMenuStrip();
notifyIcon.ContextMenuStrip.Items.Add(<>¹<EFBFBD><C2B9><EFBFBD>");
notifyIcon.ContextMenuStrip.Items.Add("<22>˳<EFBFBD>");
notifyIcon.ContextMenuStrip.ItemClicked += (object sender, ToolStripItemClickedEventArgs e) =>
{
if (e.ClickedItem.Text == "<22>˳<EFBFBD>")
{
CloseServer();
}
else if (e.ClickedItem.Text == <>¹<EFBFBD><C2B9><EFBFBD>")
{
NewShare();
}
};
NewShare();
}
private void NewShare()
{
Task.Run(() =>
{
try
{
CloseShareDesktop();
session = new RDPSession();
session.OnAttendeeConnected += Session_OnAttendeeConnected;
session.Open();
IRDPSRAPIInvitation invitation = session.Invitations.CreateInvitation(Guid.NewGuid().ToString(), "snltty", "snltty", 1024);
string invitationString = invitation.ConnectionString;
Registry.SetValue("HKEY_CURRENT_USER\\SOFTWARE\\Cmonitor", "viewerConnectStr", invitationString);
notifyIcon.Icon = Icon.FromHandle(Resources.logo_share_green.GetHicon());
notifyIcon.Text = "<22><><EFBFBD>ڹ<EFBFBD><DAB9><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>";
}
catch (Exception)
{
notifyIcon.Icon = Icon.FromHandle(Resources.logo_share_gray.GetHicon());
notifyIcon.Text = "<22><><EFBFBD><EFBFBD>ʧ<EFBFBD><CAA7>";
}
});
}
private void Session_OnAttendeeConnected(object pAttendee)
{
IRDPSRAPIAttendee attendee = (IRDPSRAPIAttendee)pAttendee;
attendee.ControlLevel = CTRL_LEVEL.CTRL_LEVEL_VIEW;
}
private void CloseShareDesktop()
{
try
{
session?.Close();
Registry.SetValue("HKEY_CURRENT_USER\\SOFTWARE\\Cmonitor", "viewerConnectStr", string.Empty);
}
catch (Exception)
{
}
}
}
public enum Mode : byte
{
Client = 0,
Server = 1,
}
}

View File

@@ -0,0 +1,400 @@
<?xml version="1.0" encoding="utf-8"?>
<root>
<!--
Microsoft ResX Schema
Version 2.0
The primary goals of this format is to allow a simple XML format
that is mostly human readable. The generation and parsing of the
various data types are done through the TypeConverter classes
associated with the data types.
Example:
... ado.net/XML headers & schema ...
<resheader name="resmimetype">text/microsoft-resx</resheader>
<resheader name="version">2.0</resheader>
<resheader name="reader">System.Resources.ResXResourceReader, System.Windows.Forms, ...</resheader>
<resheader name="writer">System.Resources.ResXResourceWriter, System.Windows.Forms, ...</resheader>
<data name="Name1"><value>this is my long string</value><comment>this is a comment</comment></data>
<data name="Color1" type="System.Drawing.Color, System.Drawing">Blue</data>
<data name="Bitmap1" mimetype="application/x-microsoft.net.object.binary.base64">
<value>[base64 mime encoded serialized .NET Framework object]</value>
</data>
<data name="Icon1" type="System.Drawing.Icon, System.Drawing" mimetype="application/x-microsoft.net.object.bytearray.base64">
<value>[base64 mime encoded string representing a byte array form of the .NET Framework object]</value>
<comment>This is a comment</comment>
</data>
There are any number of "resheader" rows that contain simple
name/value pairs.
Each data row contains a name, and value. The row also contains a
type or mimetype. Type corresponds to a .NET class that support
text/value conversion through the TypeConverter architecture.
Classes that don't support this are serialized and stored with the
mimetype set.
The mimetype is used for serialized objects, and tells the
ResXResourceReader how to depersist the object. This is currently not
extensible. For a given mimetype the value must be set accordingly:
Note - application/x-microsoft.net.object.binary.base64 is the format
that the ResXResourceWriter will generate, however the reader can
read any of the formats listed below.
mimetype: application/x-microsoft.net.object.binary.base64
value : The object must be serialized with
: System.Runtime.Serialization.Formatters.Binary.BinaryFormatter
: and then encoded with base64 encoding.
mimetype: application/x-microsoft.net.object.soap.base64
value : The object must be serialized with
: System.Runtime.Serialization.Formatters.Soap.SoapFormatter
: and then encoded with base64 encoding.
mimetype: application/x-microsoft.net.object.bytearray.base64
value : The object must be serialized into a byte array
: using a System.ComponentModel.TypeConverter
: and then encoded with base64 encoding.
-->
<xsd:schema id="root" xmlns="" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:msdata="urn:schemas-microsoft-com:xml-msdata">
<xsd:import namespace="http://www.w3.org/XML/1998/namespace" />
<xsd:element name="root" msdata:IsDataSet="true">
<xsd:complexType>
<xsd:choice maxOccurs="unbounded">
<xsd:element name="metadata">
<xsd:complexType>
<xsd:sequence>
<xsd:element name="value" type="xsd:string" minOccurs="0" />
</xsd:sequence>
<xsd:attribute name="name" use="required" type="xsd:string" />
<xsd:attribute name="type" type="xsd:string" />
<xsd:attribute name="mimetype" type="xsd:string" />
<xsd:attribute ref="xml:space" />
</xsd:complexType>
</xsd:element>
<xsd:element name="assembly">
<xsd:complexType>
<xsd:attribute name="alias" type="xsd:string" />
<xsd:attribute name="name" type="xsd:string" />
</xsd:complexType>
</xsd:element>
<xsd:element name="data">
<xsd:complexType>
<xsd:sequence>
<xsd:element name="value" type="xsd:string" minOccurs="0" msdata:Ordinal="1" />
<xsd:element name="comment" type="xsd:string" minOccurs="0" msdata:Ordinal="2" />
</xsd:sequence>
<xsd:attribute name="name" type="xsd:string" use="required" msdata:Ordinal="1" />
<xsd:attribute name="type" type="xsd:string" msdata:Ordinal="3" />
<xsd:attribute name="mimetype" type="xsd:string" msdata:Ordinal="4" />
<xsd:attribute ref="xml:space" />
</xsd:complexType>
</xsd:element>
<xsd:element name="resheader">
<xsd:complexType>
<xsd:sequence>
<xsd:element name="value" type="xsd:string" minOccurs="0" msdata:Ordinal="1" />
</xsd:sequence>
<xsd:attribute name="name" type="xsd:string" use="required" />
</xsd:complexType>
</xsd:element>
</xsd:choice>
</xsd:complexType>
</xsd:element>
</xsd:schema>
<resheader name="resmimetype">
<value>text/microsoft-resx</value>
</resheader>
<resheader name="version">
<value>2.0</value>
</resheader>
<resheader name="reader">
<value>System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
</resheader>
<resheader name="writer">
<value>System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
</resheader>
<assembly alias="System.Drawing" name="System.Drawing, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a" />
<data name="$this.Icon" type="System.Drawing.Icon, System.Drawing" mimetype="application/x-microsoft.net.object.bytearray.base64">
<value>
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
</value>
</data>
</root>

View File

@@ -1,4 +1,4 @@
namespace cmonitor.share.win
namespace cmonitor.viewer.server.win
{
internal static class Program
{
@@ -16,18 +16,25 @@ namespace cmonitor.share.win
AppDomain.CurrentDomain.UnhandledException += (a, b) =>
{
MessageBox.Show(b.ExceptionObject.ToString());
};
string shareMkey = "cmonitor/share/screen";
int shareItemMLength = 2 * 1024 * 1024;
string shareMkey = "cmonitor/share";
int shareMLength = 10;
int shareItemMLength = 1024;
int shareIndex = 5;
Mode mode = Mode.Server;
if (arg.Length > 0)
{
shareMkey = arg[0];
shareItemMLength = int.Parse(arg[1]);
shareMLength = int.Parse(arg[1]);
shareItemMLength = int.Parse(arg[2]);
shareIndex = int.Parse(arg[3]);
mode = (Mode)byte.Parse(arg[4]);
}
ApplicationConfiguration.Initialize();
Application.Run(new MainForm(shareMkey, shareItemMLength));
Application.Run(new MainForm(shareMkey, shareMLength, shareItemMLength, shareIndex, mode));
}
}
}

View File

@@ -0,0 +1,18 @@
<?xml version="1.0" encoding="utf-8"?>
<!--
https://go.microsoft.com/fwlink/?LinkID=208121.
-->
<Project>
<PropertyGroup>
<Configuration>Release</Configuration>
<Platform>Any CPU</Platform>
<PublishDir>bin\Release\net7.0-windows\publish\win-x86\</PublishDir>
<PublishProtocol>FileSystem</PublishProtocol>
<_TargetId>Folder</_TargetId>
<TargetFramework>net7.0-windows</TargetFramework>
<RuntimeIdentifier>win-x86</RuntimeIdentifier>
<SelfContained>false</SelfContained>
<PublishSingleFile>true</PublishSingleFile>
<PublishReadyToRun>false</PublishReadyToRun>
</PropertyGroup>
</Project>

View File

@@ -0,0 +1,10 @@
<?xml version="1.0" encoding="utf-8"?>
<!--
https://go.microsoft.com/fwlink/?LinkID=208121.
-->
<Project>
<PropertyGroup>
<History>True|2024-03-21T01:26:40.1376911Z;True|2024-03-21T09:24:13.2312644+08:00;True|2024-03-21T09:22:59.0517639+08:00;</History>
<LastFailureDetails />
</PropertyGroup>
</Project>

View File

@@ -0,0 +1,83 @@
//------------------------------------------------------------------------------
// <auto-generated>
// 此代码由工具生成。
// 运行时版本:4.0.30319.42000
//
// 对此文件的更改可能会导致不正确的行为,并且如果
// 重新生成代码,这些更改将会丢失。
// </auto-generated>
//------------------------------------------------------------------------------
namespace cmonitor.viewer.server.win.Properties {
using System;
/// <summary>
/// 一个强类型的资源类,用于查找本地化的字符串等。
/// </summary>
// 此类是由 StronglyTypedResourceBuilder
// 类通过类似于 ResGen 或 Visual Studio 的工具自动生成的。
// 若要添加或移除成员,请编辑 .ResX 文件,然后重新运行 ResGen
// (以 /str 作为命令选项),或重新生成 VS 项目。
[global::System.CodeDom.Compiler.GeneratedCodeAttribute("System.Resources.Tools.StronglyTypedResourceBuilder", "17.0.0.0")]
[global::System.Diagnostics.DebuggerNonUserCodeAttribute()]
[global::System.Runtime.CompilerServices.CompilerGeneratedAttribute()]
internal class Resources {
private static global::System.Resources.ResourceManager resourceMan;
private static global::System.Globalization.CultureInfo resourceCulture;
[global::System.Diagnostics.CodeAnalysis.SuppressMessageAttribute("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode")]
internal Resources() {
}
/// <summary>
/// 返回此类使用的缓存的 ResourceManager 实例。
/// </summary>
[global::System.ComponentModel.EditorBrowsableAttribute(global::System.ComponentModel.EditorBrowsableState.Advanced)]
internal static global::System.Resources.ResourceManager ResourceManager {
get {
if (object.ReferenceEquals(resourceMan, null)) {
global::System.Resources.ResourceManager temp = new global::System.Resources.ResourceManager("cmonitor.viewer.server.win.Properties.Resources", typeof(Resources).Assembly);
resourceMan = temp;
}
return resourceMan;
}
}
/// <summary>
/// 重写当前线程的 CurrentUICulture 属性,对
/// 使用此强类型资源类的所有资源查找执行重写。
/// </summary>
[global::System.ComponentModel.EditorBrowsableAttribute(global::System.ComponentModel.EditorBrowsableState.Advanced)]
internal static global::System.Globalization.CultureInfo Culture {
get {
return resourceCulture;
}
set {
resourceCulture = value;
}
}
/// <summary>
/// 查找 System.Drawing.Bitmap 类型的本地化资源。
/// </summary>
internal static System.Drawing.Bitmap logo_share_gray {
get {
object obj = ResourceManager.GetObject("logo-share-gray", resourceCulture);
return ((System.Drawing.Bitmap)(obj));
}
}
/// <summary>
/// 查找 System.Drawing.Bitmap 类型的本地化资源。
/// </summary>
internal static System.Drawing.Bitmap logo_share_green {
get {
object obj = ResourceManager.GetObject("logo-share-green", resourceCulture);
return ((System.Drawing.Bitmap)(obj));
}
}
}
}

View File

@@ -0,0 +1,127 @@
<?xml version="1.0" encoding="utf-8"?>
<root>
<!--
Microsoft ResX Schema
Version 2.0
The primary goals of this format is to allow a simple XML format
that is mostly human readable. The generation and parsing of the
various data types are done through the TypeConverter classes
associated with the data types.
Example:
... ado.net/XML headers & schema ...
<resheader name="resmimetype">text/microsoft-resx</resheader>
<resheader name="version">2.0</resheader>
<resheader name="reader">System.Resources.ResXResourceReader, System.Windows.Forms, ...</resheader>
<resheader name="writer">System.Resources.ResXResourceWriter, System.Windows.Forms, ...</resheader>
<data name="Name1"><value>this is my long string</value><comment>this is a comment</comment></data>
<data name="Color1" type="System.Drawing.Color, System.Drawing">Blue</data>
<data name="Bitmap1" mimetype="application/x-microsoft.net.object.binary.base64">
<value>[base64 mime encoded serialized .NET Framework object]</value>
</data>
<data name="Icon1" type="System.Drawing.Icon, System.Drawing" mimetype="application/x-microsoft.net.object.bytearray.base64">
<value>[base64 mime encoded string representing a byte array form of the .NET Framework object]</value>
<comment>This is a comment</comment>
</data>
There are any number of "resheader" rows that contain simple
name/value pairs.
Each data row contains a name, and value. The row also contains a
type or mimetype. Type corresponds to a .NET class that support
text/value conversion through the TypeConverter architecture.
Classes that don't support this are serialized and stored with the
mimetype set.
The mimetype is used for serialized objects, and tells the
ResXResourceReader how to depersist the object. This is currently not
extensible. For a given mimetype the value must be set accordingly:
Note - application/x-microsoft.net.object.binary.base64 is the format
that the ResXResourceWriter will generate, however the reader can
read any of the formats listed below.
mimetype: application/x-microsoft.net.object.binary.base64
value : The object must be serialized with
: System.Runtime.Serialization.Formatters.Binary.BinaryFormatter
: and then encoded with base64 encoding.
mimetype: application/x-microsoft.net.object.soap.base64
value : The object must be serialized with
: System.Runtime.Serialization.Formatters.Soap.SoapFormatter
: and then encoded with base64 encoding.
mimetype: application/x-microsoft.net.object.bytearray.base64
value : The object must be serialized into a byte array
: using a System.ComponentModel.TypeConverter
: and then encoded with base64 encoding.
-->
<xsd:schema id="root" xmlns="" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:msdata="urn:schemas-microsoft-com:xml-msdata">
<xsd:import namespace="http://www.w3.org/XML/1998/namespace" />
<xsd:element name="root" msdata:IsDataSet="true">
<xsd:complexType>
<xsd:choice maxOccurs="unbounded">
<xsd:element name="metadata">
<xsd:complexType>
<xsd:sequence>
<xsd:element name="value" type="xsd:string" minOccurs="0" />
</xsd:sequence>
<xsd:attribute name="name" use="required" type="xsd:string" />
<xsd:attribute name="type" type="xsd:string" />
<xsd:attribute name="mimetype" type="xsd:string" />
<xsd:attribute ref="xml:space" />
</xsd:complexType>
</xsd:element>
<xsd:element name="assembly">
<xsd:complexType>
<xsd:attribute name="alias" type="xsd:string" />
<xsd:attribute name="name" type="xsd:string" />
</xsd:complexType>
</xsd:element>
<xsd:element name="data">
<xsd:complexType>
<xsd:sequence>
<xsd:element name="value" type="xsd:string" minOccurs="0" msdata:Ordinal="1" />
<xsd:element name="comment" type="xsd:string" minOccurs="0" msdata:Ordinal="2" />
</xsd:sequence>
<xsd:attribute name="name" type="xsd:string" use="required" msdata:Ordinal="1" />
<xsd:attribute name="type" type="xsd:string" msdata:Ordinal="3" />
<xsd:attribute name="mimetype" type="xsd:string" msdata:Ordinal="4" />
<xsd:attribute ref="xml:space" />
</xsd:complexType>
</xsd:element>
<xsd:element name="resheader">
<xsd:complexType>
<xsd:sequence>
<xsd:element name="value" type="xsd:string" minOccurs="0" msdata:Ordinal="1" />
</xsd:sequence>
<xsd:attribute name="name" type="xsd:string" use="required" />
</xsd:complexType>
</xsd:element>
</xsd:choice>
</xsd:complexType>
</xsd:element>
</xsd:schema>
<resheader name="resmimetype">
<value>text/microsoft-resx</value>
</resheader>
<resheader name="version">
<value>2.0</value>
</resheader>
<resheader name="reader">
<value>System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
</resheader>
<resheader name="writer">
<value>System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
</resheader>
<assembly alias="System.Windows.Forms" name="System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089" />
<data name="logo-share-gray" type="System.Resources.ResXFileRef, System.Windows.Forms">
<value>..\logo-share-gray.ico;System.Drawing.Bitmap, System.Drawing, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a</value>
</data>
<data name="logo-share-green" type="System.Resources.ResXFileRef, System.Windows.Forms">
<value>..\logo-share-green.ico;System.Drawing.Bitmap, System.Drawing, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a</value>
</data>
</root>

View File

@@ -0,0 +1,79 @@
<?xml version="1.0" encoding="utf-8"?>
<assembly manifestVersion="1.0" xmlns="urn:schemas-microsoft-com:asm.v1">
<assemblyIdentity version="1.0.0.0" name="MyApplication.app"/>
<trustInfo xmlns="urn:schemas-microsoft-com:asm.v2">
<security>
<requestedPrivileges xmlns="urn:schemas-microsoft-com:asm.v3">
<!-- UAC 清单选项
如果想要更改 Windows 用户帐户控制级别,请使用
以下节点之一替换 requestedExecutionLevel 节点。
<requestedExecutionLevel level="asInvoker" uiAccess="false" />
<requestedExecutionLevel level="requireAdministrator" uiAccess="false" />
<requestedExecutionLevel level="highestAvailable" uiAccess="false" />
指定 requestedExecutionLevel 元素将禁用文件和注册表虚拟化。
如果你的应用程序需要此虚拟化来实现向后兼容性,则移除此
元素。
-->
<requestedExecutionLevel level="requireAdministrator" uiAccess="false" />
</requestedPrivileges>
</security>
</trustInfo>
<compatibility xmlns="urn:schemas-microsoft-com:compatibility.v1">
<application>
<!-- 设计此应用程序与其一起工作且已针对此应用程序进行测试的
Windows 版本的列表。取消评论适当的元素,
Windows 将自动选择最兼容的环境。 -->
<!-- Windows Vista -->
<!--<supportedOS Id="{e2011457-1546-43c5-a5fe-008deee3d3f0}" />-->
<!-- Windows 7 -->
<!--<supportedOS Id="{35138b9a-5d96-4fbd-8e2d-a2440225f93a}" />-->
<!-- Windows 8 -->
<!--<supportedOS Id="{4a2f28e3-53b9-4441-ba9c-d69d4a4a6e38}" />-->
<!-- Windows 8.1 -->
<!--<supportedOS Id="{1f676c76-80e1-4239-95bb-83d0f6d0da78}" />-->
<!-- Windows 10 -->
<!--<supportedOS Id="{8e0f7a12-bfb3-4fe8-b9a5-48fd50a15a9a}" />-->
</application>
</compatibility>
<!-- 指示该应用程序可感知 DPI 且 Windows 在 DPI 较高时将不会对其进行
自动缩放。Windows Presentation Foundation (WPF)应用程序自动感知 DPI无需
选择加入。选择加入此设置的 Windows 窗体应用程序(面向 .NET Framework 4.6)还应
在其 app.config 中将 "EnableWindowsFormsHighDpiAutoResizing" 设置设置为 "true"。
将应用程序设为感知长路径。请参阅 https://docs.microsoft.com/windows/win32/fileio/maximum-file-path-limitation -->
<!--
<application xmlns="urn:schemas-microsoft-com:asm.v3">
<windowsSettings>
<dpiAware xmlns="http://schemas.microsoft.com/SMI/2005/WindowsSettings">true</dpiAware>
<longPathAware xmlns="http://schemas.microsoft.com/SMI/2016/WindowsSettings">true</longPathAware>
</windowsSettings>
</application>
-->
<!-- 启用 Windows 公共控件和对话框的主题(Windows XP 和更高版本) -->
<!--
<dependency>
<dependentAssembly>
<assemblyIdentity
type="win32"
name="Microsoft.Windows.Common-Controls"
version="6.0.0.0"
processorArchitecture="*"
publicKeyToken="6595b64144ccf1df"
language="*"
/>
</dependentAssembly>
</dependency>
-->
</assembly>

View File

@@ -26,13 +26,25 @@
<DebugType>embedded</DebugType>
</PropertyGroup>
<ItemGroup>
<COMReference Include="RDPCOMAPILib">
<WrapperTool>tlbimp</WrapperTool>
<VersionMinor>0</VersionMinor>
<VersionMajor>1</VersionMajor>
<Guid>cc802d05-ae07-4c15-b496-db9d22aa0a84</Guid>
<Lcid>0</Lcid>
<Isolated>false</Isolated>
<EmbedInteropTypes>true</EmbedInteropTypes>
</COMReference>
</ItemGroup>
<ItemGroup>
<Content Include="favicon.ico" />
</ItemGroup>
<ItemGroup>
<PackageReference Include="SharpDX.Direct2D1" Version="4.2.0" />
<PackageReference Include="System.Drawing.Common" Version="8.0.0" />
<EmbeddedResource Include="logo-share-gray.ico" />
<EmbeddedResource Include="logo-share-green.ico" />
</ItemGroup>
<ItemGroup>
@@ -41,9 +53,18 @@
</ItemGroup>
<ItemGroup>
<Reference Include="Interop.RDPCOMAPILib">
<HintPath>Interop.RDPCOMAPILib.dll</HintPath>
</Reference>
<Compile Update="Properties\Resources.Designer.cs">
<DesignTime>True</DesignTime>
<AutoGen>True</AutoGen>
<DependentUpon>Resources.resx</DependentUpon>
</Compile>
</ItemGroup>
<ItemGroup>
<EmbeddedResource Update="Properties\Resources.resx">
<Generator>ResXFileCodeGenerator</Generator>
<LastGenOutput>Resources.Designer.cs</LastGenOutput>
</EmbeddedResource>
</ItemGroup>
</Project>

View File

@@ -0,0 +1,11 @@
<?xml version="1.0" encoding="utf-8"?>
<Project ToolsVersion="Current" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<PropertyGroup>
<_LastSelectedProfileId>D:\desktop\cmonitor\cmonitor.share.win\Properties\PublishProfiles\FolderProfile.pubxml</_LastSelectedProfileId>
</PropertyGroup>
<ItemGroup>
<Compile Update="MainForm.cs">
<SubType>Form</SubType>
</Compile>
</ItemGroup>
</Project>

Binary file not shown.

After

Width:  |  Height:  |  Size: 16 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 66 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 11 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 66 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 26 KiB

View File

@@ -1,4 +1,5 @@
using cmonitor.libs;
using common.libs;
using System.Diagnostics;
using System.Text;
@@ -129,7 +130,8 @@ namespace cmonitor.wallpaper.win
{
try
{
if (hook.CurrentKeys == Keys.None)
Keys currentKeys = (Keys)hook.CurrentKeys;
if (currentKeys == Keys.None)
{
if (lastKey != Keys.None)
{
@@ -151,11 +153,11 @@ namespace cmonitor.wallpaper.win
{
sb.Append("Alt+");
}
sb.Append(hook.CurrentKeys.ToString());
sb.Append(currentKeys.ToString());
shareMemory.Update(shareKeyBoardIndex, keyBytes, Encoding.UTF8.GetBytes(sb.ToString()));
}
lastKey = hook.CurrentKeys;
lastKey = currentKeys;
WriteWallpaper();
}
catch (Exception)
@@ -165,13 +167,26 @@ namespace cmonitor.wallpaper.win
await Task.Delay(30);
}
});
Task.Run(async () =>
{
while (cancellationTokenSource.Token.IsCancellationRequested == false)
{
if ((DateTime.Now - hook.LastDateTime).TotalMilliseconds > 1000)
{
hook.CurrentKeys = 0;
}
await Task.Delay(1000);
}
});
}
private void WriteWallpaper()
{
long time = (long)(DateTime.UtcNow.Subtract(startTime)).TotalMilliseconds;
if (time - lastTime >= 800)
{
shareMemory.Update(shareWallpaperIndex, wallpaperBytes, BitConverter.GetBytes(time));
shareMemory.IncrementVersion(shareWallpaperIndex);
lastTime = time;
}
if (shareMemory.ReadAttributeEqual(shareWallpaperIndex, ShareMemoryAttribute.Closed))

View File

@@ -39,6 +39,7 @@
<ItemGroup>
<ProjectReference Include="..\cmonitor.libs\cmonitor.libs.csproj" />
<ProjectReference Include="..\common.libs\common.libs.csproj" />
</ItemGroup>
</Project>

View File

@@ -0,0 +1,7 @@
import { sendWebsocketMsg } from './request'
export const screenDisplay = (names, state) => {
return sendWebsocketMsg('display/update', {
names, state
}, false, 1000);
}

View File

@@ -14,9 +14,3 @@ export const screenClip = (name, data) => {
clip: data
}, false, 1000);
}
export const screenDisplay = (names, state) => {
return sendWebsocketMsg('screen/display', {
names, state
}, false, 1000);
}

View File

@@ -0,0 +1,5 @@
import { sendWebsocketMsg } from './request'
export const viewerUpdate = (data) => {
return sendWebsocketMsg('viewer/update', data);
}

View File

@@ -1,14 +1,14 @@
<template>
<div class="checkbox-wrap absolute flex flex-column">
<div class="head flex">
<span>
<span v-if="!state.single">
<el-checkbox :indeterminate="state.isIndeterminate" v-model="state.checkAll" @change="handleCheckAllChange" :label="state.title" />
</span>
<span class="flex-1"></span>
<slot name="title"></slot>
</div>
<div class="body flex-1 scrollbar">
<el-checkbox-group v-model="state.checkList" @change="handleChange">
<el-checkbox-group :max="state.single?1:65535" v-model="state.checkList" @change="handleChange">
<ul>
<template v-for="(item,index) in state.data" :key="index">
<li class="flex">
@@ -31,7 +31,7 @@
<script>
import { computed, onMounted, reactive, watch } from 'vue'
export default {
props: ['title', 'items', 'data', 'label', 'text'],
props: ['title', 'items', 'data', 'label', 'text', 'single'],
emits: ['change'],
setup(props, { emit }) {
@@ -39,6 +39,7 @@ export default {
title: props.title,
label: props.label,
text: props.text || props.label,
single: props.single,
data: computed(() => props.data),
checkList: props.items.map(c => c[props.label]),
checkAll: false,

View File

@@ -5,29 +5,13 @@
<el-button @click="handleDisplay(true)">亮屏</el-button>
<el-button @click="handleDisplay(false)">息屏</el-button>
</div>
<div class="subitem">
<span class="label">屏幕共享</span>
<el-button @click="handleShare">开始</el-button>
</div>
</div>
<el-dialog title="选择分享设备" destroy-on-close v-model="pluginState.screen.showShare" center align-center width="94%">
<div class="t-c">
<el-select v-model="pluginState.screen.device" placeholder="选择分享设备" size="large">
<el-option v-for="item in globalState.devices" :key="item.MachineName" :label="item.MachineName" :value="item.MachineName" />
</el-select>
</div>
<template #footer>
<el-button @click="handleCancel"> </el-button>
<el-button type="success" plain @click="handleConfirm"> </el-button>
</template>
</el-dialog>
</template>
<script>
import { ElMessage } from 'element-plus';
import { injectPluginState } from '../../provide'
import { screenDisplay } from '../../../../apis/screen'
import { screenDisplay } from '../../../../apis/display'
import { injectGlobalData } from '@/views/provide';
export default {
setup() {
@@ -47,17 +31,7 @@ export default {
});
}
const handleShare = () => {
pluginState.value.screen.showShare = true;
}
const handleCancel = () => {
pluginState.value.screen.showShare = false;
}
const handleConfirm = () => {
ElMessage.success('操作成功');
}
return { pluginState, globalState, handleDisplay, handleShare, handleCancel, handleConfirm }
return { pluginState, globalState, handleDisplay }
}
}
</script>

View File

@@ -4,20 +4,11 @@
</template>
<script>
import { onMounted, watch } from 'vue';
import { injectPluginState } from '../../provide'
import { injectGlobalData } from '@/views/provide';
export default {
components: {},
setup() {
const pluginState = injectPluginState();
const globalState = injectGlobalData();
watch(() => pluginState.value.screen.shareUpdateFlag, () => { });
onMounted(() => { })
return { pluginState }
return {}
}
}
</script>

View File

@@ -5,7 +5,6 @@ export default {
field() {
return {
Screen: {
share: false,
regionImgs: [], //局部图
fullImg: null, //全图
@@ -208,10 +207,8 @@ export default {
},
state: {
screen: {
showShare: false,
device: '',
devices: [],
shareUpdateFlag: 0
devices: []
}
},

View File

@@ -0,0 +1,66 @@
<template>
<div class="item">
<div class="subitem">
<span class="label">屏幕共享</span>
<el-button @click="handleShare">开始</el-button>
</div>
</div>
<el-dialog title="选择分享设备" destroy-on-close v-model="pluginState.viewer.showShare" center align-center width="94%">
<div class="t-c">
<el-select v-model="pluginState.viewer.device" placeholder="选择分享设备" size="large">
<el-option v-for="item in globalState.devices" :key="item.MachineName" :label="item.MachineName" :value="item.MachineName" />
</el-select>
</div>
<template #footer>
<el-button @click="handleCancel"> </el-button>
<el-button type="success" plain @click="handleConfirm"> </el-button>
</template>
</el-dialog>
</template>
<script>
import { ElMessage } from 'element-plus';
import { injectPluginState } from '../../provide'
import { injectGlobalData } from '@/views/provide';
import { viewerUpdate } from '@/apis/viewer';
export default {
setup() {
const pluginState = injectPluginState();
const globalState = injectGlobalData();
const handleShare = () => {
pluginState.value.viewer.showShare = true;
}
const handleCancel = () => {
pluginState.value.viewer.showShare = false;
}
const handleConfirm = () => {
const clients = pluginState.value.command.devices.map(c => c.MachineName);
if (clients.length == 0) {
ElMessage.error('请至少选择一个目标设备');
return;
}
if (!pluginState.value.viewer.device) {
ElMessage.error('请选择一个共享设备');
return;
}
viewerUpdate({
Open: true,
Server: pluginState.value.viewer.device,
Clients: clients,
}).then(() => {
pluginState.viewer.showShare = false;
ElMessage.success('操作成功');
}).catch(() => {
ElMessage.error('操作失败');
});
}
return { pluginState, globalState, handleShare, handleCancel, handleConfirm }
}
}
</script>
<style lang="stylus" scoped></style>

View File

@@ -0,0 +1,25 @@
<template>
<div>
</div>
</template>
<script>
import { onMounted, watch } from 'vue';
import { injectPluginState } from '../../provide'
import { injectGlobalData } from '@/views/provide';
export default {
components: {},
setup() {
const pluginState = injectPluginState();
const globalState = injectGlobalData();
watch(() => pluginState.value.viewer.shareUpdateFlag, () => { });
onMounted(() => { })
return { pluginState }
}
}
</script>
<style lang="stylus" scoped></style>

View File

@@ -1,10 +1,9 @@
<template>
<div class="screen-share-wrap" v-if="data.Screen.share">
<div class="viewer-share-wrap" v-if="data.Viewer.share && data.Viewer.mode == 'server'">
<div class="inner">
<h5>
<span>正在共享屏幕</span>
</h5>
<div>
<el-popconfirm confirm-button-text="确认" cancel-button-text="取消" title="确认结束共享吗?" @confirm="handleConfirm">
<template #reference>
@@ -20,6 +19,7 @@
import { reactive } from 'vue'
import { ElMessage } from 'element-plus';
import { injectPluginState } from '../../provide';
import { viewerUpdate } from '../../../../apis/viewer';
export default {
props: ['data'],
setup(props) {
@@ -28,7 +28,16 @@ export default {
const state = reactive({
loading: false
});
const handleConfirm = () => { }
const handleConfirm = () => {
viewerUpdate({
open: false,
server: props.data.MachineName
}).then(() => {
ElMessage.success('已操作!')
}).catch(() => {
ElMessage.error('操作失败!')
});
}
return {
data: props.data, state, handleConfirm
@@ -38,7 +47,7 @@ export default {
</script>
<style lang="stylus" scoped>
.screen-share-wrap {
.viewer-share-wrap {
position: absolute;
left: 0;
top: 0;

View File

@@ -0,0 +1,29 @@
export default {
field() {
return {
Viewer: {
share: false,
mode: 'server'
}
};
},
state: {
viewer: {
showShare: false,
device: '',
devices: [],
shareUpdateFlag: 0
}
},
init() {
},
uninit() {
},
update(item, report) {
if (!report.Viewer) return;
item.Viewer.share = report.Viewer.Value;
item.Viewer.mode = ['client', 'server'][report.Viewer.Mode];
}
}

View File

@@ -5,13 +5,21 @@ const globalDataSymbol = Symbol();
export const provideGlobalData = () => {
const globalData = ref({
//当前登录用户
username: '',
//默认用户
publicUserName: 'snltty',
//用户配置
usernames: {},
//已连接
connected: false,
//需要更新规则 用 watch
updateRuleFlag: 0,
//需要更新设备 用 watch
updateDeviceFlag: 0,
//所有设备
allDevices: [],
//当前用户设备
devices: computed(() => {
const user = globalData.value.usernames[globalData.value.username];
if (user) {
@@ -19,7 +27,9 @@ export const provideGlobalData = () => {
}
return [];
}),
//当前设备
currentDevice: { MachineName: '' },
//需要报告数据的设备
reportNames: []
});
subWebsocketState((state) => {

View File

@@ -1,55 +1,47 @@
using cmonitor.api;
using cmonitor.api.services;
using cmonitor.client;
using cmonitor.client.reports.active;
using cmonitor.client.reports.light;
using cmonitor.client.reports.hijack;
using cmonitor.client.reports.llock;
using cmonitor.client.reports.screen;
using cmonitor.client.reports.volume;
using cmonitor.client.reports.notify;
using cmonitor.client.reports.command;
using cmonitor.client.reports;
using cmonitor.client.reports.share;
using cmonitor.client.reports.system;
using cmonitor.service;
using cmonitor.service.messengers.active;
using cmonitor.service.messengers.hijack;
using cmonitor.service.messengers.llock;
using cmonitor.service.messengers.report;
using cmonitor.service.messengers.screen;
using cmonitor.service.messengers.sign;
using cmonitor.service.messengers.volume;
using cmonitor.service.messengers.wallpaper;
using cmonitor.service.messengers.keyboard;
using cmonitor.service.messengers.system;
using cmonitor.service.messengers.light;
using cmonitor.service.messengers.share;
using cmonitor.service.messengers.notify;
using cmonitor.service.messengers.setting;
using cmonitor.web;
using common.libs;
using common.libs;
using common.libs.database;
using common.libs.extends;
using Microsoft.Extensions.DependencyInjection;
using System.Net;
using System.Reflection;
using System.Text.Json.Serialization;
using cmonitor.client.reports.keyboard;
using cmonitor.client.reports.wallpaper;
using cmonitor.client.reports.snatch;
using cmonitor.service.messengers.snatch;
using cmonitor.libs;
using cmonitor.client.reports.wlan;
using cmonitor.service.messengers.wlan;
using common.libs.winapis;
using cmonitor.startup;
using cmonitor.config;
namespace cmonitor
{
internal class Program
{
static async Task Main(string[] args)
{
Init(args);
//初始化配置文件
Config config = new Config();
config.Elevated = args.Any(c => c.Contains("elevated"));
Assembly[] assemblies = AppDomain.CurrentDomain.GetAssemblies();
StartupTransfer.Init();
//依赖注入
ServiceProvider serviceProvider = null;
ServiceCollection serviceCollection = new ServiceCollection();
//注入
serviceCollection.AddSingleton((e) => serviceProvider);
serviceCollection.AddSingleton((a) => config);
serviceCollection.AddTransient(typeof(IConfigDataProvider<>), typeof(ConfigDataFileProvider<>));
StartupTransfer.Add(serviceCollection, config, assemblies);
//运行
serviceProvider = serviceCollection.BuildServiceProvider();
StartupTransfer.Use(serviceProvider, config, assemblies);
GCHelper.FlushMemory();
await Helper.Await();
}
private static void Init(string[] args)
{
//单服务
Mutex mutex = new Mutex(true, System.Diagnostics.Process.GetCurrentProcess().ProcessName, out bool isAppRunning);
@@ -57,25 +49,6 @@ namespace cmonitor
{
Environment.Exit(1);
}
//日志输出
LoggerConsole();
//读取参数
Dictionary<string, string> dic = ArgumentParser.Parse(args, out string error);
#if RELEASE
//提权
if (dic.ContainsKey("elevated") == false)
{
Win32Interop.RelaunchElevated();
}
#endif
//初始化配置文件
Config config = new Config();
InitConfig(config, dic);
//全局异常
AppDomain.CurrentDomain.UnhandledException += (a, b) =>
{
@@ -85,242 +58,24 @@ namespace cmonitor
ThreadPool.SetMinThreads(1024, 1024);
ThreadPool.SetMaxThreads(65535, 65535);
//日志输出
LoggerConsole();
//注入对象
ServiceProvider serviceProvider = null;
ServiceCollection serviceCollection = new ServiceCollection();
//注入 依赖注入服务供应 使得可以在别的地方通过注入的方式获得 ServiceProvider 以用来获取其它服务
serviceCollection.AddSingleton((e) => serviceProvider);
//注入
serviceCollection.AddSingleton<Config>((a) => config);
AddSingleton(serviceCollection, config);
serviceProvider = serviceCollection.BuildServiceProvider();
//运行服务
RunService(serviceProvider, config);
GCHelper.FlushMemory();
await Helper.Await();
}
private static void RunService(ServiceProvider serviceProvider, Config config)
{
Assembly[] assemblies = AppDomain.CurrentDomain.GetAssemblies();
MessengerResolver messengerResolver = serviceProvider.GetService<MessengerResolver>();
messengerResolver.LoadMessenger(assemblies);
if (config.IsServer)
#if RELEASE
//提权
if (args.Any(c=>c.Contains("elevated")) == false)
{
Logger.Instance.Info($"start server");
//api
IClientServer clientServer = serviceProvider.GetService<IClientServer>();
clientServer.LoadPlugins(assemblies);
clientServer.Websocket();
Logger.Instance.Info($"api listen:{config.ApiPort}");
//web
IWebServer webServer = serviceProvider.GetService<IWebServer>();
webServer.Start();
Logger.Instance.Info($"web listen:{config.WebPort}");
//服务
TcpServer tcpServer = serviceProvider.GetService<TcpServer>();
tcpServer.Start();
Logger.Instance.Info($"service listen:{config.ServicePort}");
}
if (config.IsCLient)
{
Logger.Instance.Info($"start client");
Logger.Instance.Info($"server ip {config.Server}");
ReportTransfer report = serviceProvider.GetService<ReportTransfer>();
report.LoadPlugins(assemblies);
ShareMemory shareMemory = serviceProvider.GetService<ShareMemory>();
shareMemory.InitLocal();
shareMemory.InitGlobal();
shareMemory.StartLoop();
ClientTransfer clientTransfer = serviceProvider.GetService<ClientTransfer>();
}
}
private static void AddSingleton(ServiceCollection serviceCollection, Config config)
{
serviceCollection.AddTransient(typeof(IConfigDataProvider<>), typeof(ConfigDataFileProvider<>));
//客户端
serviceCollection.AddSingleton<ClientSignInState>();
serviceCollection.AddSingleton<ClientTransfer>();
serviceCollection.AddSingleton<ClientConfig>();
//内存共享
ShareMemory shareMemory = new ShareMemory(config.ShareMemoryKey, config.ShareMemoryLength, config.ShareMemoryItemSize);
serviceCollection.AddSingleton<ShareMemory>((a) => shareMemory);
#region
serviceCollection.AddSingleton<ReportTransfer>();
serviceCollection.AddSingleton<ActiveWindowReport>();
if (OperatingSystem.IsWindows()) serviceCollection.AddSingleton<IActiveWindow, ActiveWindowWindows>();
else if (OperatingSystem.IsLinux()) serviceCollection.AddSingleton<IActiveWindow, ActiveWindowLinux>();
else if (OperatingSystem.IsMacOS()) serviceCollection.AddSingleton<IActiveWindow, ActiveWindowMacOS>();
serviceCollection.AddSingleton<CommandReport>();
serviceCollection.AddSingleton<ICommandLine, CommandLineWindows>();
serviceCollection.AddSingleton<HijackConfig>();
serviceCollection.AddSingleton<HijackReport>();
if (OperatingSystem.IsWindows()) serviceCollection.AddSingleton<IHijack, HijackWindows>();
else if (OperatingSystem.IsLinux()) serviceCollection.AddSingleton<IHijack, HijackLinux>();
else if (OperatingSystem.IsMacOS()) serviceCollection.AddSingleton<IHijack, HijackMacOS>();
serviceCollection.AddSingleton<KeyboardReport>();
if (OperatingSystem.IsWindows()) serviceCollection.AddSingleton<IKeyboard, KeyboardWindows>();
else if (OperatingSystem.IsLinux()) serviceCollection.AddSingleton<IKeyboard, KeyboardLinux>();
else if (OperatingSystem.IsMacOS()) serviceCollection.AddSingleton<IKeyboard, KeyboardMacOS>();
serviceCollection.AddSingleton<LightReport>();
if (OperatingSystem.IsWindows()) serviceCollection.AddSingleton<ILight, LightWindows>();
else if (OperatingSystem.IsLinux()) serviceCollection.AddSingleton<ILight, LightLinux>();
else if (OperatingSystem.IsMacOS()) serviceCollection.AddSingleton<ILight, LightMacOS>();
serviceCollection.AddSingleton<LLockReport>();
if (OperatingSystem.IsWindows()) serviceCollection.AddSingleton<ILLock, LLockWindows>();
else if (OperatingSystem.IsLinux()) serviceCollection.AddSingleton<ILLock, LLockLinux>();
else if (OperatingSystem.IsMacOS()) serviceCollection.AddSingleton<ILLock, LLockMacOS>();
serviceCollection.AddSingleton<NotifyReport>();
if (OperatingSystem.IsWindows()) serviceCollection.AddSingleton<INotify, NotifyWindows>();
else if (OperatingSystem.IsLinux()) serviceCollection.AddSingleton<INotify, NotifyLinux>();
else if (OperatingSystem.IsMacOS()) serviceCollection.AddSingleton<INotify, NotifyMacOS>();
serviceCollection.AddSingleton<ScreenReport>();
if (OperatingSystem.IsWindows()) serviceCollection.AddSingleton<IScreen, ScreenWindows>();
else if (OperatingSystem.IsLinux()) serviceCollection.AddSingleton<IScreen, ScreenLinux>();
else if (OperatingSystem.IsMacOS()) serviceCollection.AddSingleton<IScreen, ScreenMacOS>();
serviceCollection.AddSingleton<VolumeReport>();
if (OperatingSystem.IsWindows()) serviceCollection.AddSingleton<IVolume, VolumeWindows>();
else if (OperatingSystem.IsLinux()) serviceCollection.AddSingleton<IVolume, VolumeLinux>();
else if (OperatingSystem.IsMacOS()) serviceCollection.AddSingleton<IVolume, VolumeMacOS>();
serviceCollection.AddSingleton<WallpaperReport>();
if (OperatingSystem.IsWindows()) serviceCollection.AddSingleton<IWallpaper, WallpaperWindows>();
else if (OperatingSystem.IsLinux()) serviceCollection.AddSingleton<IWallpaper, WallpaperLinux>();
else if (OperatingSystem.IsMacOS()) serviceCollection.AddSingleton<IWallpaper, WallpaperMacOS>();
serviceCollection.AddSingleton<SystemReport>();
if (OperatingSystem.IsWindows()) serviceCollection.AddSingleton<ISystem, SystemWindows>();
else if (OperatingSystem.IsLinux()) serviceCollection.AddSingleton<ISystem, SystemLinux>();
else if (OperatingSystem.IsMacOS()) serviceCollection.AddSingleton<ISystem, SystemMacOS>();
serviceCollection.AddSingleton<SnatchReport>();
if (OperatingSystem.IsWindows()) serviceCollection.AddSingleton<ISnatch, SnatchWindows>();
else if (OperatingSystem.IsLinux()) serviceCollection.AddSingleton<ISnatch, SnatchLinux>();
else if (OperatingSystem.IsMacOS()) serviceCollection.AddSingleton<ISnatch, SnatchMacOS>();
serviceCollection.AddSingleton<WlanReport>();
if (OperatingSystem.IsWindows()) serviceCollection.AddSingleton<IWlan, WlanWindows>();
else if (OperatingSystem.IsLinux()) serviceCollection.AddSingleton<IWlan, WlanLinux>();
else if (OperatingSystem.IsMacOS()) serviceCollection.AddSingleton<IWlan, WlanMacOS>();
serviceCollection.AddSingleton<ShareReport>();
#endregion
#region
serviceCollection.AddSingleton<TcpServer>();
serviceCollection.AddSingleton<MessengerSender>();
serviceCollection.AddSingleton<MessengerResolver>();
serviceCollection.AddSingleton<SignCaching>();
serviceCollection.AddSingleton<SignInMessenger>();
serviceCollection.AddSingleton<ReportMessenger>();
serviceCollection.AddSingleton<CommandMessenger>();
serviceCollection.AddSingleton<HijackMessenger>();
serviceCollection.AddSingleton<ActiveMessenger>();
serviceCollection.AddSingleton<LLockMessenger>();
serviceCollection.AddSingleton<ScreenMessenger>();
serviceCollection.AddSingleton<VolumeMessenger>();
serviceCollection.AddSingleton<WallpaperMessenger>();
serviceCollection.AddSingleton<LightMessenger>();
serviceCollection.AddSingleton<ShareMessenger>();
serviceCollection.AddSingleton<NotifyMessenger>();
serviceCollection.AddSingleton<SettingMessenger>();
serviceCollection.AddSingleton<KeyboardMessenger>();
serviceCollection.AddSingleton<SystemMessenger>();
serviceCollection.AddSingleton<SnatchMessenger>();
serviceCollection.AddSingleton<WlanMessenger>();
#endregion
#region api
serviceCollection.AddSingleton<RuleConfig>();
serviceCollection.AddSingleton<IClientServer, ClientServer>();
serviceCollection.AddSingleton<SignInClientService>();
serviceCollection.AddSingleton<CommandClientService>();
serviceCollection.AddSingleton<ReportClientService>();
serviceCollection.AddSingleton<HijackClientService>();
serviceCollection.AddSingleton<ActiveClientService>();
serviceCollection.AddSingleton<LLockClientService>();
serviceCollection.AddSingleton<ScreenClientService>();
serviceCollection.AddSingleton<VolumeClientService>();
serviceCollection.AddSingleton<WallpaperClientService>();
serviceCollection.AddSingleton<LightClientService>();
serviceCollection.AddSingleton<ShareClientService>();
serviceCollection.AddSingleton<NotifyClientService>();
serviceCollection.AddSingleton<SettingClientService>();
serviceCollection.AddSingleton<SystemClientService>();
serviceCollection.AddSingleton<KeyboardClientService>();
serviceCollection.AddSingleton<SnatchClientService>();
serviceCollection.AddSingleton<ISnatachCaching, SnatachCachingMemory>();
serviceCollection.AddSingleton<WlanClientService>();
#endregion
//web
serviceCollection.AddSingleton<IWebServer, WebServer>();
}
private static void InitConfig(Config config, Dictionary<string, string> dic)
{
try
{
config.Server = IPAddress.Parse(dic["server"]);
config.Name = dic["name"];
config.WebPort = int.Parse(dic["web"]);
config.ApiPort = int.Parse(dic["api"]);
config.ServicePort = int.Parse(dic["service"]);
config.ShareMemoryKey = dic["share-key"];
config.ShareMemoryLength = int.Parse(dic["share-len"]);
config.ShareMemoryItemSize = int.Parse(dic["share-item-len"]);
config.ReportDelay = int.Parse(dic["report-delay"]);
config.ScreenScale = float.Parse(dic["screen-scale"]);
config.ScreenDelay = int.Parse(dic["screen-delay"]);
config.Elevated = dic.ContainsKey("elevated");
Logger.Instance.Debug($"config:{config.ToJsonFormat()}");
//Logger.Instance.Debug($"args:{string.Join(" ", args)}");
config.IsCLient = dic.ContainsKey("mode") && dic["mode"].Contains("client");
config.IsServer = dic.ContainsKey("mode") && dic["mode"].Contains("server");
}
catch (Exception ex)
{
Logger.Instance.Error(ex);
common.libs.winapis.Win32Interop.RelaunchElevated();
}
#endif
}
private static void LoggerConsole()
{
Logger.Instance.LoggerLevel = LoggerTypes.DEBUG;
if (Directory.Exists("log") == false)
if (Directory.Exists("logs") == false)
{
Directory.CreateDirectory("log");
Directory.CreateDirectory("logs");
}
Logger.Instance.OnLogger += (model) =>
{
@@ -347,7 +102,7 @@ namespace cmonitor
Console.ForegroundColor = currentForeColor;
try
{
using StreamWriter sw = File.AppendText(Path.Combine("log", $"{DateTime.Now:yyyy-MM-dd}.log"));
using StreamWriter sw = File.AppendText(Path.Combine("logs", $"{DateTime.Now:yyyy-MM-dd}.log"));
sw.WriteLine(line);
sw.Flush();
sw.Close();
@@ -358,209 +113,10 @@ namespace cmonitor
}
};
}
}
public sealed class Config
{
public int WebPort { get; set; } = 1800;
public int ApiPort { get; set; } = 1801;
public int ServicePort { get; set; } = 1802;
public IPAddress Server { get; set; } = IPAddress.Loopback;
public string WebRoot { get; set; } = "./web/";
public string Name { get; set; } = Dns.GetHostName();
public int ReportDelay { get; set; } = 30;
public float ScreenScale { get; set; } = 0.2f;
public int ScreenDelay { get; set; } = 30;
/// <summary>
/// 0项保留
/// </summary>
public string ShareMemoryKey { get; set; } = "cmonitor/share";
public int ShareMemoryLength { get; set; } = 10;
public int ShareMemoryItemSize { get; set; } = 1024;
[JsonIgnore]
public bool SaveSetting { get; set; } = true;
[JsonIgnore]
public bool WakeUp { get; set; } = true;
[JsonIgnore]
public bool VolumeMasterPeak { get; set; } = false;
[JsonIgnore]
public string Version { get; set; } = "1.0.0.1";
[JsonIgnore]
public bool IsCLient { get; set; }
[JsonIgnore]
public bool IsServer { get; set; }
[JsonIgnore]
public bool Elevated { get; set; }
//键盘
public const int ShareMemoryKeyBoardIndex = 1;
//壁纸
public const int ShareMemoryWallpaperIndex = 2;
//锁屏
public const int ShareMemoryLLockIndex = 3;
//SAS
public const int ShareMemorySASIndex = 4;
//抢答,问题,和回答分开存,为了保证数据安全性
public const int ShareSnatchQuestionIndex = 5;
public const int ShareSnatchAnswerIndex = 6;
public const int ShareScreenShareIndex = 7;
}
public class ArgumentParser
{
public static Dictionary<string, string> Parse(string[] args, out string error)
{
Dictionary<string, string> dic = new Dictionary<string, string>();
for (int i = 0; i < args.Length; i++)
{
if (args[i].IndexOf("--") == 0)
{
if (i + 1 < args.Length && args[i + 1].IndexOf("--") == -1)
{
dic.Add(args[i].Substring(2), args[i + 1]);
i++;
}
else
{
dic.Add(args[i].Substring(2), string.Empty);
}
}
}
Validate(dic, out error);
return dic;
}
static bool Validate(Dictionary<string, string> dic, out string error)
{
error = string.Empty;
return ValidateMode(dic) &&
ValidateServer(dic, out error)
&& ValidateName(dic, out error)
&& ValidatePort(dic, out error)
&& ValidateMemoryKey(dic, out error)
&& ValidateScreenScale(dic, out error)
&& ValidateReport(dic, out error)
&& ValidateElevated(dic, out error);
}
static bool ValidateMode(Dictionary<string, string> dic)
{
//模式
if (dic.ContainsKey("mode") == false || (dic["mode"].Contains("client") == false && dic["mode"].Contains("server") == false))
{
dic["mode"] = "server,client";
}
return true;
}
static bool ValidateServer(Dictionary<string, string> dic, out string error)
{
error = string.Empty;
//服务器地址
if (dic.ContainsKey("server") == false || string.IsNullOrWhiteSpace(dic["server"]))
{
dic["server"] = IPAddress.Loopback.ToString();
}
return true;
}
static bool ValidateName(Dictionary<string, string> dic, out string error)
{
error = string.Empty;
//服务器地址
if (dic.ContainsKey("name") == false || string.IsNullOrWhiteSpace(dic["name"]))
{
dic["name"] = Dns.GetHostName();
if (dic["name"].Length > 12)
{
dic["name"] = dic["name"].Substring(0, 12);
}
}
return true;
}
static bool ValidatePort(Dictionary<string, string> dic, out string error)
{
error = string.Empty;
//界面接口
if (dic.ContainsKey("web") == false || string.IsNullOrWhiteSpace(dic["web"]))
{
dic["web"] = "1800";
}
//管理接口
if (dic.ContainsKey("api") == false || string.IsNullOrWhiteSpace(dic["api"]))
{
dic["api"] = "1801";
}
//服务接口
if (dic.ContainsKey("service") == false || string.IsNullOrWhiteSpace(dic["service"]))
{
dic["service"] = "1802";
}
return true;
}
static bool ValidateMemoryKey(Dictionary<string, string> dic, out string error)
{
error = string.Empty;
if (dic.ContainsKey("share-key") == false || string.IsNullOrWhiteSpace(dic["share-key"]))
{
dic["share-key"] = "cmonitor/share";
}
if (dic.ContainsKey("share-len") == false || string.IsNullOrWhiteSpace(dic["share-len"]))
{
dic["share-len"] = "10";
}
if (dic.ContainsKey("share-item-len") == false || string.IsNullOrWhiteSpace(dic["share-item-len"]))
{
dic["share-item-len"] = "1024";
}
return true;
}
static bool ValidateScreenScale(Dictionary<string, string> dic, out string error)
{
error = string.Empty;
if (dic.ContainsKey("screen-scale") == false || string.IsNullOrWhiteSpace(dic["screen-scale"]))
{
dic["screen-scale"] = "0.2";
}
if (dic.ContainsKey("screen-delay") == false || string.IsNullOrWhiteSpace(dic["screen-delay"]))
{
dic["screen-delay"] = "200";
}
return true;
}
static bool ValidateReport(Dictionary<string, string> dic, out string error)
{
error = string.Empty;
if (dic.ContainsKey("report-delay") == false || string.IsNullOrWhiteSpace(dic["report-delay"]))
{
dic["report-delay"] = "30";
}
return true;
}
static bool ValidateElevated(Dictionary<string, string> dic, out string error)
{
error = string.Empty;
if (dic.ContainsKey("elevated"))
{
dic["elevated"] = "1";
}
return true;
}
}
}

View File

@@ -1,4 +1,5 @@
using cmonitor.api.websocket;
using cmonitor.config;
using common.libs;
using common.libs.extends;
using Microsoft.Extensions.DependencyInjection;
@@ -12,7 +13,7 @@ namespace cmonitor.api
/// <summary>
/// 前段接口服务
/// </summary>
public sealed class ClientServer : IClientServer
public sealed class ApiServer : IApiServer
{
private readonly Dictionary<string, PluginPathCacheInfo> plugins = new();
private readonly ConcurrentDictionary<uint, ConnectionTimeInfo> connectionTimes = new();
@@ -22,7 +23,7 @@ namespace cmonitor.api
private WebSocketServer server;
private readonly Config config;
public ClientServer(ServiceProvider serviceProvider, Config config)
public ApiServer(ServiceProvider serviceProvider, Config config)
{
this.serviceProvider = serviceProvider;
this.config = config;
@@ -37,10 +38,12 @@ namespace cmonitor.api
Type voidType = typeof(void);
IEnumerable<Type> types = assemblys.SelectMany(c => c.GetTypes());
foreach (Type item in types.Where(c => c.GetInterfaces().Contains(typeof(IClientService))))
IEnumerable<Type> types = assemblys.SelectMany(c => c.GetTypes()).Where(c => c.GetInterfaces().Contains(typeof(IApiController)));
Logger.Instance.Warning($"load server apis:{string.Join(",", types.Select(c => c.Name))}");
foreach (Type item in types)
{
string path = item.Name.Replace("ClientService", "");
string path = item.Name.Replace("ApiController", "");
object obj = serviceProvider.GetService(item);
foreach (MethodInfo method in item.GetMethods(BindingFlags.Instance | BindingFlags.Public | BindingFlags.DeclaredOnly))
{
@@ -69,7 +72,7 @@ namespace cmonitor.api
server = new WebSocketServer();
try
{
server.Start(System.Net.IPAddress.Any, config.ApiPort);
server.Start(System.Net.IPAddress.Any, config.Server.ApiPort);
}
catch (Exception ex)
{
@@ -92,7 +95,7 @@ namespace cmonitor.api
{
timeInfo.DateTime = DateTime.Now;
}
var req = message.DeJson<ClientServiceRequestInfo>();
var req = message.DeJson<ApiControllerRequestInfo>();
req.Connection = connection;
OnMessage(req).ContinueWith((result) =>
{
@@ -107,23 +110,23 @@ namespace cmonitor.api
/// </summary>
/// <param name="model"></param>
/// <returns></returns>
public async Task<ClientServiceResponseInfo> OnMessage(ClientServiceRequestInfo model)
public async Task<ApiControllerResponseInfo> OnMessage(ApiControllerRequestInfo model)
{
model.Path = model.Path.ToLower();
if (plugins.TryGetValue(model.Path, out PluginPathCacheInfo plugin) == false)
{
return new ClientServiceResponseInfo
return new ApiControllerResponseInfo
{
Content = "not exists this path",
RequestId = model.RequestId,
Path = model.Path,
Code = ClientServiceResponseCodes.NotFound
Code = ApiControllerResponseCodes.NotFound
};
}
try
{
ClientServiceParamsInfo param = new ClientServiceParamsInfo
ApiControllerParamsInfo param = new ApiControllerParamsInfo
{
RequestId = model.RequestId,
Content = model.Content,
@@ -146,10 +149,10 @@ namespace cmonitor.api
resultObject = resultAsync;
}
}
return new ClientServiceResponseInfo
return new ApiControllerResponseInfo
{
Code = param.Code,
Content = param.Code != ClientServiceResponseCodes.Error ? resultObject : param.ErrorMessage,
Content = param.Code != ApiControllerResponseCodes.Error ? resultObject : param.ErrorMessage,
RequestId = model.RequestId,
Path = model.Path,
};
@@ -157,12 +160,12 @@ namespace cmonitor.api
catch (Exception ex)
{
Logger.Instance.Error(ex);
return new ClientServiceResponseInfo
return new ApiControllerResponseInfo
{
Content = ex.Message,
RequestId = model.RequestId,
Path = model.Path,
Code = ClientServiceResponseCodes.Error
Code = ApiControllerResponseCodes.Error
};
}
}
@@ -173,9 +176,9 @@ namespace cmonitor.api
{
try
{
byte[] bytes = JsonSerializer.Serialize(new ClientServiceResponseInfo
byte[] bytes = JsonSerializer.Serialize(new ApiControllerResponseInfo
{
Code = ClientServiceResponseCodes.Success,
Code = ApiControllerResponseCodes.Success,
Content = content,
Path = path,
RequestId = 0
@@ -208,9 +211,9 @@ namespace cmonitor.api
{
try
{
Memory<byte> headMemory = JsonSerializer.Serialize(new ClientServiceResponseInfo
Memory<byte> headMemory = JsonSerializer.Serialize(new ApiControllerResponseInfo
{
Code = ClientServiceResponseCodes.Success,
Code = ApiControllerResponseCodes.Success,
Content = name,
Path = path,
RequestId = 0
@@ -255,9 +258,9 @@ namespace cmonitor.api
{
if (connection.Connected == false) return;
byte[] bytes = JsonSerializer.Serialize(new ClientServiceResponseInfo
byte[] bytes = JsonSerializer.Serialize(new ApiControllerResponseInfo
{
Code = ClientServiceResponseCodes.Success,
Code = ApiControllerResponseCodes.Success,
Content = content,
Path = path,
RequestId = 0

View File

@@ -0,0 +1,33 @@
using cmonitor.config;
using cmonitor.startup;
using common.libs;
using Microsoft.Extensions.DependencyInjection;
using System.Reflection;
namespace cmonitor.api
{
public sealed class ApiStartup : IStartup
{
public void AddClient(ServiceCollection serviceCollection, Config config, Assembly[] assemblies)
{
}
public void AddServer(ServiceCollection serviceCollection, Config config, Assembly[] assemblies)
{
serviceCollection.AddSingleton<IApiServer, ApiServer>();
}
public void UseClient(ServiceProvider serviceProvider, Config config, Assembly[] assemblies)
{
}
public void UseServer(ServiceProvider serviceProvider, Config config, Assembly[] assemblies)
{
Logger.Instance.Info($"start api server");
IApiServer clientServer = serviceProvider.GetService<IApiServer>();
clientServer.LoadPlugins(assemblies);
clientServer.Websocket();
Logger.Instance.Info($"api listen:{config.Server.ApiPort}");
}
}
}

View File

@@ -6,12 +6,12 @@ namespace cmonitor.api
/// <summary>
/// 前段接口
/// </summary>
public interface IClientService { }
public interface IApiController { }
/// <summary>
/// 前段接口response
/// </summary>
public sealed class ClientServiceResponseInfo
public sealed class ApiControllerResponseInfo
{
/// <summary>
/// 路径
@@ -24,7 +24,7 @@ namespace cmonitor.api
/// <summary>
/// 状态码
/// </summary>
public ClientServiceResponseCodes Code { get; set; } = ClientServiceResponseCodes.Success;
public ApiControllerResponseCodes Code { get; set; } = ApiControllerResponseCodes.Success;
/// <summary>
/// 数据
/// </summary>
@@ -34,7 +34,7 @@ namespace cmonitor.api
/// <summary>
/// 前端接口request
/// </summary>
public sealed class ClientServiceRequestInfo
public sealed class ApiControllerRequestInfo
{
[JsonIgnore]
public WebsocketConnection Connection { get; set; }
@@ -55,7 +55,7 @@ namespace cmonitor.api
/// <summary>
/// 前端接口执行参数
/// </summary>
public sealed class ClientServiceParamsInfo
public sealed class ApiControllerParamsInfo
{
public WebsocketConnection Connection { get; set; }
/// <summary>
@@ -69,7 +69,7 @@ namespace cmonitor.api
/// <summary>
/// 状态码
/// </summary>
public ClientServiceResponseCodes Code { get; private set; } = ClientServiceResponseCodes.Success;
public ApiControllerResponseCodes Code { get; private set; } = ApiControllerResponseCodes.Success;
/// <summary>
/// 错误信息
/// </summary>
@@ -80,7 +80,7 @@ namespace cmonitor.api
/// </summary>
/// <param name="code"></param>
/// <param name="errormsg"></param>
public void SetCode(ClientServiceResponseCodes code, string errormsg = "")
public void SetCode(ApiControllerResponseCodes code, string errormsg = "")
{
Code = code;
ErrorMessage = errormsg;
@@ -91,14 +91,14 @@ namespace cmonitor.api
/// <param name="msg"></param>
public void SetErrorMessage(string msg)
{
Code = ClientServiceResponseCodes.Error;
Code = ApiControllerResponseCodes.Error;
ErrorMessage = msg;
}
}
/// <summary>
/// 前端接口状态码
/// </summary>
public enum ClientServiceResponseCodes : byte
public enum ApiControllerResponseCodes : byte
{
/// <summary>
/// 成功
@@ -119,13 +119,13 @@ namespace cmonitor.api
/// 前端接口标识特性
/// </summary>
[AttributeUsage(AttributeTargets.Method)]
public class ClientServiceAttribute : Attribute
public class ApiControllerAttribute : Attribute
{
/// <summary>
/// 参数类型
/// </summary>
public Type Param { get; set; }
public ClientServiceAttribute(Type param)
public ApiControllerAttribute(Type param)
{
Param = param;
}

View File

@@ -6,7 +6,7 @@ namespace cmonitor.api
/// <summary>
/// 前端接口服务
/// </summary>
public interface IClientServer
public interface IApiServer
{
/// <summary>
/// websocket

View File

@@ -1,166 +0,0 @@
using cmonitor.client.reports.hijack;
using cmonitor.client.reports.screen;
using common.libs.database;
using System.ComponentModel.DataAnnotations.Schema;
namespace cmonitor.client
{
[Table("client")]
public sealed class ClientConfig
{
private readonly IConfigDataProvider<ClientConfig> configDataProvider;
private readonly Config config;
public ClientConfig() { }
public ClientConfig(IConfigDataProvider<ClientConfig> configDataProvider, Config config)
{
this.configDataProvider = configDataProvider;
this.config = config;
ClientConfig clientConfig = configDataProvider.Load().Result ?? new ClientConfig();
LLock = clientConfig.LLock;
Wallpaper = clientConfig.Wallpaper;
WallpaperUrl = clientConfig.WallpaperUrl;
HijackConfig = clientConfig.HijackConfig;
HijackIds = clientConfig.HijackIds;
WindowNames = clientConfig.WindowNames;
WindowIds = clientConfig.WindowIds;
UserSid = clientConfig.UserSid;
Wlan = clientConfig.Wlan;
WlanAuto = clientConfig.WlanAuto;
SaveTask();
}
private void SaveTask()
{
Task.Factory.StartNew(async () =>
{
while (true)
{
try
{
if (updated && config.SaveSetting)
{
Save();
}
}
catch (Exception)
{
}
await Task.Delay(5000);
}
}, TaskCreationOptions.LongRunning);
}
private bool updated = false;
private bool _llock;
public bool LLock
{
get => _llock; set
{
_llock = value;
updated = true;
}
}
private bool _wallpaper;
public bool Wallpaper
{
get => _wallpaper; set
{
_wallpaper = value;
updated = true;
}
}
private string _wallpaperUrl;
public string WallpaperUrl
{
get => _wallpaperUrl; set
{
_wallpaperUrl = value;
updated = true;
}
}
private HijackConfig _hijackConfig = new HijackConfig();
public HijackConfig HijackConfig
{
get => _hijackConfig; set
{
_hijackConfig = value;
updated = true;
}
}
private uint[] _hijackIds = Array.Empty<uint>();
public uint[] HijackIds
{
get => _hijackIds; set
{
_hijackIds = value;
updated = true;
}
}
private string[] _windowNames = Array.Empty<string>();
public string[] WindowNames
{
get => _windowNames; set
{
_windowNames = value;
updated = true;
}
}
private uint[] _windowIds = Array.Empty<uint>();
public uint[] WindowIds
{
get => _windowIds; set
{
_windowIds = value;
updated = true;
}
}
private string _userSid = string.Empty;
public string UserSid
{
get => _userSid; set
{
_userSid = value;
updated = true;
}
}
private string _wlan = string.Empty;
public string Wlan
{
get => _wlan; set
{
_wlan = value;
updated = true;
}
}
private bool _wlanAuto;
public bool WlanAuto
{
get => _wlanAuto; set
{
_wlanAuto = value;
updated = true;
}
}
public void Save()
{
configDataProvider.Save(this).Wait();
}
}
}

View File

@@ -1,4 +1,4 @@
using cmonitor.service;
using cmonitor.server;
namespace cmonitor.client
{

View File

@@ -1,5 +1,6 @@
using cmonitor.service;
using cmonitor.service.messengers.sign;
using cmonitor.config;
using cmonitor.plugins.signIn.messenger;
using cmonitor.server;
using common.libs;
using common.libs.extends;
using MemoryPack;
@@ -8,28 +9,25 @@ using System.Net.Sockets;
namespace cmonitor.client
{
public sealed class ClientTransfer
public sealed class ClientSignInTransfer
{
private readonly ClientSignInState clientSignInState;
private readonly Config config;
private readonly TcpServer tcpServer;
private readonly MessengerSender messengerSender;
public ClientTransfer(ClientSignInState clientSignInState, Config config, TcpServer tcpServer, MessengerSender messengerSender)
public ClientSignInTransfer(ClientSignInState clientSignInState, Config config, TcpServer tcpServer, MessengerSender messengerSender)
{
this.clientSignInState = clientSignInState;
this.config = config;
this.tcpServer = tcpServer;
this.messengerSender = messengerSender;
if (config.IsCLient)
SignInTask();
tcpServer.OnDisconnected += (hashcode) =>
{
SignInTask();
tcpServer.OnDisconnected += (hashcode) =>
{
clientSignInState.PushNetworkDisabled();
};
}
clientSignInState.PushNetworkDisabled();
};
}
private void SignInTask()
@@ -58,7 +56,7 @@ namespace cmonitor.client
}
private async Task SignIn()
{
IPAddress[] ips = new IPAddress[] { config.Server };
IPAddress[] ips = new IPAddress[] { config.Client.ServerEP.Address };
if (Logger.Instance.LoggerLevel <= LoggerTypes.DEBUG)
Logger.Instance.Info($"get ip:{ips.ToJsonFormat()}");
@@ -68,7 +66,7 @@ namespace cmonitor.client
{
try
{
IPEndPoint remote = new IPEndPoint(ip, config.ServicePort);
IPEndPoint remote = new IPEndPoint(ip, config.Client.ServerEP.Port);
//Logger.Instance.Info($"connect server {remote}");
Socket socket = new Socket(ip.AddressFamily, SocketType.Stream, ProtocolType.Tcp);
socket.KeepAlive();
@@ -86,7 +84,7 @@ namespace cmonitor.client
MessengerId = (ushort)SignInMessengerIds.SignIn,
Payload = MemoryPackSerializer.Serialize(new SignInfo
{
MachineName = config.Name,
MachineName = config.Client.Name,
Version = config.Version
})
});

View File

@@ -0,0 +1,61 @@
using cmonitor.client.runningConfig;
using cmonitor.client.report;
using cmonitor.client.ruleConfig;
using cmonitor.config;
using cmonitor.libs;
using cmonitor.startup;
using common.libs;
using Microsoft.Extensions.DependencyInjection;
using System.Reflection;
namespace cmonitor.client
{
public sealed class ClientStartup : IStartup
{
public void AddClient(ServiceCollection serviceCollection, Config config, Assembly[] assemblies)
{
serviceCollection.AddSingleton<RuleConfig>();
serviceCollection.AddSingleton<ClientReportTransfer>();
serviceCollection.AddSingleton<ClientSignInState>();
serviceCollection.AddSingleton<ClientSignInTransfer>();
if (OperatingSystem.IsWindows()) serviceCollection.AddSingleton<IRunningConfig, RunningConfigWindows>();
else if (OperatingSystem.IsLinux()) serviceCollection.AddSingleton<IRunningConfig, RunningConfigLinux>();
else if (OperatingSystem.IsMacOS()) serviceCollection.AddSingleton<IRunningConfig, RunningConfigMacOS>();
//内存共享
ShareMemory shareMemory = new ShareMemory(config.Client.ShareMemoryKey, config.Client.ShareMemoryCount, config.Client.ShareMemorySize);
serviceCollection.AddSingleton<ShareMemory>((a) => shareMemory);
}
public void AddServer(ServiceCollection serviceCollection, Config config, Assembly[] assemblies)
{
}
public void UseClient(ServiceProvider serviceProvider, Config config, Assembly[] assemblies)
{
Logger.Instance.Info($"start client");
Logger.Instance.Info($"server ip {config.Server}");
Logger.Instance.Info($"start client report transfer");
ClientReportTransfer report = serviceProvider.GetService<ClientReportTransfer>();
report.LoadPlugins(assemblies);
Logger.Instance.Info($"start client share memory");
ShareMemory shareMemory = serviceProvider.GetService<ShareMemory>();
shareMemory.InitLocal();
shareMemory.InitGlobal();
shareMemory.StartLoop();
Logger.Instance.Info($"start client signin transfer");
ClientSignInTransfer clientTransfer = serviceProvider.GetService<ClientSignInTransfer>();
}
public void UseServer(ServiceProvider serviceProvider, Config config, Assembly[] assemblies)
{
}
}
}

View File

@@ -1,21 +1,15 @@
using cmonitor.service.messengers.sign;
using cmonitor.service;
using cmonitor.config;
using cmonitor.plugins.report.messenger;
using cmonitor.server;
using common.libs;
using common.libs.extends;
using MemoryPack;
using Microsoft.Extensions.DependencyInjection;
using common.libs.extends;
using System.Reflection;
namespace cmonitor.client.reports
namespace cmonitor.client.report
{
public interface IReport
{
public string Name { get; }
public object GetReports(ReportType reportType);
}
public sealed class ReportTransfer : IReport
public sealed class ClientReportTransfer
{
public string Name => string.Empty;
@@ -24,32 +18,26 @@ namespace cmonitor.client.reports
private readonly ServiceProvider serviceProvider;
private readonly Config config;
private List<IReport> reports;
private List<IClientReport> reports;
private Dictionary<string, object> reportObj;
private ReportType reportType = ReportType.Full | ReportType.Trim;
public ReportTransfer(ClientSignInState clientSignInState, MessengerSender messengerSender, ServiceProvider serviceProvider, Config config)
public ClientReportTransfer(ClientSignInState clientSignInState, MessengerSender messengerSender, ServiceProvider serviceProvider, Config config)
{
this.clientSignInState = clientSignInState;
this.messengerSender = messengerSender;
this.serviceProvider = serviceProvider;
this.config = config;
if (config.IsCLient)
{
ReportTask();
}
}
public object GetReports(ReportType reportType)
{
return null;
ReportTask();
}
public void LoadPlugins(Assembly[] assembs)
{
IEnumerable<Type> types = ReflectionHelper.GetInterfaceSchieves(assembs, typeof(IReport));
reports = types.Select(c => (IReport)serviceProvider.GetService(c)).Where(c => string.IsNullOrWhiteSpace(c.Name) == false).ToList();
IEnumerable<Type> types = ReflectionHelper.GetInterfaceSchieves(assembs, typeof(IClientReport));
reports = types.Select(c => (IClientReport)serviceProvider.GetService(c)).Where(c => string.IsNullOrWhiteSpace(c.Name) == false).ToList();
reportObj = new Dictionary<string, object>(reports.Count);
Logger.Instance.Info($"load reports:{string.Join(",", reports.Select(c => c.Name))}");
}
private uint reportFlag = 0;
@@ -81,15 +69,15 @@ namespace cmonitor.client.reports
if (Logger.Instance.LoggerLevel <= LoggerTypes.DEBUG)
Logger.Instance.Error(ex);
}
await Task.Delay(config.ReportDelay);
await Task.Delay(30);
}
}, TaskCreationOptions.LongRunning);
}
private async Task SendReport()
{
reportObj.Clear();
foreach (IReport item in reports)
foreach (IClientReport item in reports)
{
if (string.IsNullOrWhiteSpace(item.Name) == false)
{
@@ -116,9 +104,4 @@ namespace cmonitor.client.reports
}
}
}
public enum ReportType : byte
{
Full = 1, Trim = 2
}
}

View File

@@ -0,0 +1,13 @@
namespace cmonitor.client.report
{
public interface IClientReport
{
public string Name { get; }
public object GetReports(ReportType reportType);
}
}

View File

@@ -0,0 +1,16 @@
namespace cmonitor.client.report
{
public abstract class ReportInfo
{
public abstract int HashCode();
private int hashcode = 0;
public bool Updated()
{
int code = HashCode();
bool updated = code != hashcode;
hashcode = code;
return updated;
}
}
}

View File

@@ -0,0 +1,13 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace cmonitor.client.report
{
public enum ReportType : byte
{
Full = 1, Trim = 2
}
}

View File

@@ -1,64 +0,0 @@
using cmonitor.libs;
namespace cmonitor.client.reports.llock
{
public sealed class LLockReport : IReport
{
public string Name => "LLock";
private LLockReportInfo report = new LLockReportInfo();
private readonly ClientConfig clientConfig;
private readonly ILLock lLock;
private readonly ShareMemory shareMemory;
private long version = 0;
public LLockReport(Config config, ClientConfig clientConfig, ILLock lLock, ShareMemory shareMemory,ClientSignInState clientSignInState)
{
this.clientConfig = clientConfig;
this.lLock = lLock;
this.shareMemory = shareMemory;
if (config.IsCLient)
{
clientSignInState.NetworkFirstEnabledHandle +=()=> { LockScreen(clientConfig.LLock); };
}
}
DateTime startTime = new DateTime(1970, 1, 1);
public object GetReports(ReportType reportType)
{
bool updated = shareMemory.ReadVersionUpdated(Config.ShareMemoryLLockIndex,ref version);
if (reportType == ReportType.Full || updated)
{
long value = shareMemory.ReadValueInt64(Config.ShareMemoryLLockIndex);
clientConfig.LLock = report.LockScreen = value > 0 && (long)(DateTime.UtcNow.Subtract(startTime)).TotalMilliseconds - value < 1000;
return report;
}
return null;
}
public void LockScreen(bool open)
{
clientConfig.LLock = open;
Task.Run(async () =>
{
shareMemory.AddAttribute(Config.ShareMemoryLLockIndex, ShareMemoryAttribute.Closed);
await Task.Delay(100);
lLock.Set(open);
});
}
public void LockSystem()
{
lLock.LockSystem();
}
}
public sealed class LLockReportInfo
{
public bool LockScreen { get; set; }
}
}

View File

@@ -1,54 +0,0 @@
using System;
using System.Runtime.InteropServices;
using FFmpeg.AutoGen.Abstractions;
namespace cmonitor.client.reports.screen.h264;
internal static class FFmpegHelper
{
public static unsafe string av_strerror(int error)
{
var bufferSize = 1024;
var buffer = stackalloc byte[bufferSize];
ffmpeg.av_strerror(error, buffer, (ulong)bufferSize);
var message = Marshal.PtrToStringAnsi((IntPtr)buffer);
return message;
}
public static int ThrowExceptionIfError(this int error)
{
if (error < 0) throw new ApplicationException(av_strerror(error));
return error;
}
public static void Initialize()
{
RegisterFFmpegBinaries();
FFmpeg.AutoGen.Bindings.DynamicallyLoaded.DynamicallyLoadedBindings.Initialize();
}
internal static void RegisterFFmpegBinaries()
{
if (RuntimeInformation.IsOSPlatform(OSPlatform.Windows))
{
var current = Environment.CurrentDirectory;
while (current != null)
{
var ffmpegBinaryPath = Path.Combine(current, "ffmpeg");
if (Directory.Exists(ffmpegBinaryPath))
{
//Console.WriteLine($"FFmpeg binaries found in: {ffmpegBinaryPath}");
FFmpeg.AutoGen.Bindings.DynamicallyLoaded.DynamicallyLoadedBindings.LibrariesPath = ffmpegBinaryPath;
return;
}
current = Directory.GetParent(current)?.FullName;
}
}
else
throw new NotSupportedException(); // fell free add support for platform of your choose
}
}

View File

@@ -1,49 +0,0 @@
using FFmpeg.AutoGen;
using System.Drawing;
namespace cmonitor.client.reports.screen.h264
{
public unsafe class H264VideoStreamDecoder
{
private readonly AVCodecContext* _pCodecContext;
private readonly AVFrame* _pFrame;
private readonly AVPacket* _pPacket;
public H264VideoStreamDecoder(int fps, Size frameSize, string[] args)
{
var codecId = AVCodecID.AV_CODEC_ID_H264;
var pCodec = ffmpeg.avcodec_find_decoder(codecId);
if (pCodec == null) throw new InvalidOperationException("Codec not found.");
_pCodecContext = ffmpeg.avcodec_alloc_context3(pCodec);
_pCodecContext->width = frameSize.Width;
_pCodecContext->height = frameSize.Height;
_pCodecContext->time_base = new AVRational { num = 1, den = fps };
_pCodecContext->pix_fmt = AVPixelFormat.AV_PIX_FMT_YUV420P;
foreach (var arg in args)
{
var optionName = arg.Split('=')[0];
var value = arg.Split('=')[1];
ffmpeg.av_opt_set(_pCodecContext->priv_data, optionName, value, 0);
}
//ffmpeg.av_opt_set(_pCodecContext->priv_data, "preset", "veryfast", 0);
//ffmpeg.av_opt_set(_pCodecContext->priv_data, "tune", "zerolatency", 0);
ffmpeg.avcodec_open2(_pCodecContext, pCodec, null).ThrowExceptionIfError();
}
public AVFrame Decoder(AVPacket packet)
{
var frame = ffmpeg.av_frame_alloc();
int error;
do
{
ffmpeg.avcodec_send_packet(_pCodecContext, &packet).ThrowExceptionIfError();
error = ffmpeg.avcodec_receive_frame(_pCodecContext, frame);
} while (error == ffmpeg.AVERROR(ffmpeg.EAGAIN));
ffmpeg.av_packet_unref(&packet);
return *frame;
}
}
}

View File

@@ -1,106 +0,0 @@
using System.Drawing;
using System.Runtime.InteropServices;
using FFmpeg.AutoGen.Abstractions;
namespace cmonitor.client.reports.screen.h264;
public sealed unsafe class H264VideoStreamEncoder : IDisposable
{
private readonly Size _frameSize;
private readonly int _linesizeU;
private readonly int _linesizeV;
private readonly int _linesizeY;
private readonly AVCodec* _pCodec;
private readonly AVCodecContext* _pCodecContext;
private readonly int _uSize;
private readonly int _ySize;
public H264VideoStreamEncoder(int fps, Size frameSize)
{
_frameSize = frameSize;
var codecId = AVCodecID.AV_CODEC_ID_H264;
_pCodec = ffmpeg.avcodec_find_encoder(codecId);
if (_pCodec == null) throw new InvalidOperationException("Codec not found.");
_pCodecContext = ffmpeg.avcodec_alloc_context3(_pCodec);
_pCodecContext->width = frameSize.Width;
_pCodecContext->height = frameSize.Height;
_pCodecContext->time_base = new AVRational { num = 1, den = fps };
_pCodecContext->pix_fmt = AVPixelFormat.AV_PIX_FMT_YUV420P;
ffmpeg.av_opt_set(_pCodecContext->priv_data, "preset", "superfast", 0);
//ffmpeg.av_opt_set(_pCodecContext->priv_data, "-b:v", "50K", 0);
//ffmpeg.av_opt_set(_pCodecContext->priv_data, "-minrate", "50K", 0);
//ffmpeg.av_opt_set(_pCodecContext->priv_data, "-maxrate", "5000K", 0);
//ffmpeg.av_opt_set(_pCodecContext->priv_data, "-bufsize", "5000K", 0);
ffmpeg.avcodec_open2(_pCodecContext, _pCodec, null).ThrowExceptionIfError();
_linesizeY = frameSize.Width;
_linesizeU = frameSize.Width / 2;
_linesizeV = frameSize.Width / 2;
_ySize = _linesizeY * frameSize.Height;
_uSize = _linesizeU * frameSize.Height / 2;
}
public void Dispose()
{
ffmpeg.avcodec_close(_pCodecContext);
ffmpeg.av_free(_pCodecContext);
ffmpeg.av_free(_pCodec);
}
public void SendFrame(AVFrame frame)
{
if (frame.format != (int)_pCodecContext->pix_fmt)
throw new ArgumentException("Invalid pixel format.", nameof(frame));
if (frame.width != _frameSize.Width) throw new ArgumentException("Invalid width.", nameof(frame));
if (frame.height != _frameSize.Height) throw new ArgumentException("Invalid height.", nameof(frame));
if (frame.linesize[0] < _linesizeY) throw new ArgumentException("Invalid Y linesize.", nameof(frame));
if (frame.linesize[1] < _linesizeU) throw new ArgumentException("Invalid U linesize.", nameof(frame));
if (frame.linesize[2] < _linesizeV) throw new ArgumentException("Invalid V linesize.", nameof(frame));
if (frame.data[1] - frame.data[0] < _ySize)
throw new ArgumentException("Invalid Y data size.", nameof(frame));
if (frame.data[2] - frame.data[1] < _uSize)
throw new ArgumentException("Invalid U data size.", nameof(frame));
try
{
ffmpeg.avcodec_send_frame(_pCodecContext, &frame).ThrowExceptionIfError();
}
catch (Exception)
{
}
finally
{
ffmpeg.av_frame_unref(&frame);
}
}
public byte[] ReceivePacket()
{
AVPacket* pPacket = ffmpeg.av_packet_alloc();
try
{
ffmpeg.av_packet_unref(pPacket);
int response = ffmpeg.avcodec_receive_packet(_pCodecContext, pPacket);
if(response == 0)
{
byte[] bytes = new byte[pPacket->size];
Marshal.Copy((IntPtr)pPacket->data, bytes, 0, pPacket->size);
return bytes;
}
}
finally
{
ffmpeg.av_packet_free(&pPacket);
}
return Array.Empty<byte>();
}
}

View File

@@ -1,63 +0,0 @@
using System.Drawing;
using System.Runtime.InteropServices;
using FFmpeg.AutoGen;
namespace cmonitor.client.reports.screen.h264;
public sealed unsafe class VideoConverter : IDisposable
{
private readonly SwsContext* _pConvertContext;
public VideoConverter(Size sourceSize, AVPixelFormat sourcePixelFormat,
Size destinationSize, AVPixelFormat destinationPixelFormat)
{
_pConvertContext = ffmpeg.sws_getContext(sourceSize.Width,
sourceSize.Height,
sourcePixelFormat,
destinationSize.Width,
destinationSize.Height,
destinationPixelFormat,
ffmpeg.SWS_FAST_BILINEAR,
null,
null,
null);
if (_pConvertContext == null)
throw new ApplicationException("Could not initialize the conversion context.");
var convertedFrameBufferSize = ffmpeg.av_image_get_buffer_size(destinationPixelFormat,
destinationSize.Width,
destinationSize.Height,
1);
var convertedFrameBufferPtr = Marshal.AllocHGlobal(convertedFrameBufferSize);
var dstData = new byte_ptrArray4();
var dstLinesize = new int_array4();
ffmpeg.av_image_fill_arrays(ref dstData,
ref dstLinesize,
(byte*)convertedFrameBufferPtr,
destinationPixelFormat,
destinationSize.Width,
destinationSize.Height,
1);
}
public void Dispose()
{
}
public AVFrame Convert(AVFrame sourceFrame)
{
var dstData = new byte_ptrArray4();
var dstLinesize = new int_array4();
ffmpeg.sws_scale(_pConvertContext,
sourceFrame.data,
sourceFrame.linesize,
0,
sourceFrame.height,
dstData,
dstLinesize);
return new AVFrame();
}
}

View File

@@ -1,83 +0,0 @@
using System;
using System.Drawing;
using System.Runtime.InteropServices;
using FFmpeg.AutoGen.Abstractions;
namespace cmonitor.client.reports.screen.h264;
public sealed unsafe class VideoFrameConverter : IDisposable
{
private readonly IntPtr _convertedFrameBufferPtr;
private readonly Size _destinationSize;
private readonly byte_ptr4 _dstData;
private readonly int4 _dstLinesize;
private readonly SwsContext* _pConvertContext;
public VideoFrameConverter(Size sourceSize, AVPixelFormat sourcePixelFormat,
Size destinationSize, AVPixelFormat destinationPixelFormat)
{
_destinationSize = destinationSize;
_pConvertContext = ffmpeg.sws_getContext(sourceSize.Width,
sourceSize.Height,
sourcePixelFormat,
destinationSize.Width,
destinationSize.Height,
destinationPixelFormat,
ffmpeg.SWS_FAST_BILINEAR,
null,
null,
null);
if (_pConvertContext == null)
throw new ApplicationException("Could not initialize the conversion context.");
var convertedFrameBufferSize = ffmpeg.av_image_get_buffer_size(destinationPixelFormat,
destinationSize.Width,
destinationSize.Height,
1);
_convertedFrameBufferPtr = Marshal.AllocHGlobal(convertedFrameBufferSize);
_dstData = new byte_ptr4();
_dstLinesize = new int4();
ffmpeg.av_image_fill_arrays(ref _dstData,
ref _dstLinesize,
(byte*)_convertedFrameBufferPtr,
destinationPixelFormat,
destinationSize.Width,
destinationSize.Height,
1);
}
public void Dispose()
{
Marshal.FreeHGlobal(_convertedFrameBufferPtr);
ffmpeg.sws_freeContext(_pConvertContext);
}
public FFmpeg.AutoGen.Abstractions.AVFrame Convert(FFmpeg.AutoGen.Abstractions.AVFrame sourceFrame)
{
ffmpeg.sws_scale(_pConvertContext,
sourceFrame.data,
sourceFrame.linesize,
0,
sourceFrame.height,
_dstData,
_dstLinesize);
var data = new byte_ptr8();
data.UpdateFrom(_dstData);
var linesize = new int8();
linesize.UpdateFrom(_dstLinesize);
ffmpeg.av_frame_unref(&sourceFrame);
return new FFmpeg.AutoGen.Abstractions.AVFrame
{
data = data,
linesize = linesize,
width = _destinationSize.Width,
height = _destinationSize.Height
};
}
}

View File

@@ -1,125 +0,0 @@
using System.Drawing;
using System.Runtime.InteropServices;
using FFmpeg.AutoGen.Abstractions;
namespace cmonitor.client.reports.screen.h264;
public sealed unsafe class VideoStreamDecoder : IDisposable
{
private readonly AVCodecContext* _pCodecContext;
private readonly AVFormatContext* _pFormatContext;
private readonly AVFrame* _pFrame;
private readonly AVPacket* _pPacket;
private readonly AVFrame* _receivedFrame;
private readonly int _streamIndex;
public VideoStreamDecoder(string url, AVHWDeviceType HWDeviceType = AVHWDeviceType.AV_HWDEVICE_TYPE_NONE)
{
_pFormatContext = ffmpeg.avformat_alloc_context();
_receivedFrame = ffmpeg.av_frame_alloc();
var pFormatContext = _pFormatContext;
ffmpeg.avformat_open_input(&pFormatContext, url, null, null).ThrowExceptionIfError();
ffmpeg.avformat_find_stream_info(_pFormatContext, null).ThrowExceptionIfError();
AVCodec* codec = null;
_streamIndex = ffmpeg
.av_find_best_stream(_pFormatContext, AVMediaType.AVMEDIA_TYPE_VIDEO, -1, -1, &codec, 0)
.ThrowExceptionIfError();
_pCodecContext = ffmpeg.avcodec_alloc_context3(codec);
if (HWDeviceType != AVHWDeviceType.AV_HWDEVICE_TYPE_NONE)
{
ffmpeg.av_hwdevice_ctx_create(&_pCodecContext->hw_device_ctx, HWDeviceType, null, null, 0)
.ThrowExceptionIfError();
}
ffmpeg.avcodec_parameters_to_context(_pCodecContext, _pFormatContext->streams[_streamIndex]->codecpar)
.ThrowExceptionIfError();
ffmpeg.avcodec_open2(_pCodecContext, codec, null).ThrowExceptionIfError();
CodecName = ffmpeg.avcodec_get_name(codec->id);
FrameSize = new Size(_pCodecContext->width, _pCodecContext->height);
PixelFormat = _pCodecContext->pix_fmt;
_pPacket = ffmpeg.av_packet_alloc();
_pFrame = ffmpeg.av_frame_alloc();
}
public string CodecName { get; }
public Size FrameSize { get; }
public AVPixelFormat PixelFormat { get; }
public void Dispose()
{
var pFrame = _pFrame;
ffmpeg.av_frame_free(&pFrame);
var pPacket = _pPacket;
ffmpeg.av_packet_free(&pPacket);
ffmpeg.avcodec_close(_pCodecContext);
var pFormatContext = _pFormatContext;
ffmpeg.avformat_close_input(&pFormatContext);
}
public bool TryDecodeNextFrame(out AVFrame frame)
{
ffmpeg.av_frame_unref(_pFrame);
ffmpeg.av_frame_unref(_receivedFrame);
int error;
do
{
try
{
do
{
ffmpeg.av_packet_unref(_pPacket);
error = ffmpeg.av_read_frame(_pFormatContext, _pPacket);
if (error == ffmpeg.AVERROR_EOF)
{
frame = *_pFrame;
return false;
}
error.ThrowExceptionIfError();
} while (_pPacket->stream_index != _streamIndex);
ffmpeg.avcodec_send_packet(_pCodecContext, _pPacket).ThrowExceptionIfError();
}
finally
{
ffmpeg.av_packet_unref(_pPacket);
}
error = ffmpeg.avcodec_receive_frame(_pCodecContext, _pFrame);
} while (error == ffmpeg.AVERROR(ffmpeg.EAGAIN));
error.ThrowExceptionIfError();
if (_pCodecContext->hw_device_ctx != null)
{
ffmpeg.av_hwframe_transfer_data(_receivedFrame, _pFrame, 0).ThrowExceptionIfError();
frame = *_receivedFrame;
}
else
frame = *_pFrame;
return true;
}
public IReadOnlyDictionary<string, string> GetContextInfo()
{
AVDictionaryEntry* tag = null;
var result = new Dictionary<string, string>();
while ((tag = ffmpeg.av_dict_get(_pFormatContext->metadata, "", tag, ffmpeg.AV_DICT_IGNORE_SUFFIX)) != null)
{
var key = Marshal.PtrToStringAnsi((IntPtr)tag->key);
var value = Marshal.PtrToStringAnsi((IntPtr)tag->value);
result.Add(key, value);
}
return result;
}
}

View File

@@ -1,7 +0,0 @@
namespace cmonitor.client.reports.wallpaper
{
public interface IWallpaper
{
public void Set(bool value, string url);
}
}

View File

@@ -1,9 +0,0 @@
namespace cmonitor.client.reports.wallpaper
{
public sealed class WallpaperLinux : IWallpaper
{
public void Set(bool value, string url)
{
}
}
}

View File

@@ -1,9 +0,0 @@
namespace cmonitor.client.reports.wallpaper
{
public sealed class WallpaperMacOS : IWallpaper
{
public void Set(bool value, string url)
{
}
}
}

View File

@@ -1,81 +0,0 @@
using cmonitor.libs;
namespace cmonitor.client.reports.wallpaper
{
public sealed class WallpaperReport : IReport
{
public string Name => "Wallpaper";
private WallpaperReportInfo report = new WallpaperReportInfo();
private readonly ClientConfig clientConfig;
private readonly IWallpaper wallpaper;
private readonly ShareMemory shareMemory;
private long version = 0;
private bool opened = false;
public WallpaperReport(Config config, ClientConfig clientConfig, IWallpaper wallpaper, ShareMemory shareMemory, ClientSignInState clientSignInState)
{
this.clientConfig = clientConfig;
this.wallpaper = wallpaper;
this.shareMemory = shareMemory;
if (config.IsCLient)
{
clientSignInState.NetworkFirstEnabledHandle += () => { Update(clientConfig.Wallpaper, clientConfig.WallpaperUrl); };
WallpaperTask();
}
}
DateTime startTime = new DateTime(1970, 1, 1);
public object GetReports(ReportType reportType)
{
if (reportType == ReportType.Full || shareMemory.ReadVersionUpdated(Config.ShareMemoryWallpaperIndex, ref version))
{
report.Value = Running();
return report;
}
return null;
}
public void Update(bool open, string url)
{
opened = open;
clientConfig.Wallpaper = open;
clientConfig.WallpaperUrl = url;
Task.Run(async () =>
{
shareMemory.AddAttribute(Config.ShareMemoryWallpaperIndex, ShareMemoryAttribute.Closed);
await Task.Delay(100);
wallpaper.Set(open, url);
});
}
private void WallpaperTask()
{
Task.Run(async () =>
{
while (true)
{
if (opened)
{
if (Running() == false)
{
Update(clientConfig.Wallpaper, clientConfig.WallpaperUrl);
}
}
await Task.Delay(5000);
}
});
}
private bool Running()
{
long value = shareMemory.ReadValueInt64(Config.ShareMemoryWallpaperIndex);
return value > 0 && (long)(DateTime.UtcNow.Subtract(startTime)).TotalMilliseconds - value < 1000;
}
}
public sealed class WallpaperReportInfo
{
public bool Value { get; set; }
}
}

View File

@@ -1,22 +0,0 @@
using common.libs;
namespace cmonitor.client.reports.wallpaper
{
public sealed class WallpaperWindows : IWallpaper
{
private readonly Config config;
public WallpaperWindows(Config config)
{
this.config = config;
}
public void Set(bool value, string url)
{
if (value)
{
CommandHelper.Windows(string.Empty, new string[] {
$"start cmonitor.wallpaper.win.exe \"{url}\" {config.ShareMemoryKey} {config.ShareMemoryLength} {config.ShareMemoryItemSize} {Config.ShareMemoryKeyBoardIndex} {Config.ShareMemoryWallpaperIndex}"
});
}
}
}
}

View File

@@ -1,80 +0,0 @@
using common.libs.winapis;
namespace cmonitor.client.reports.wlan
{
public sealed class WlanReport : IReport
{
public string Name => "Wlan";
private readonly Config config;
private readonly ClientConfig clientConfig;
private readonly IWlan wlan;
public WlanReport(Config config, ClientConfig clientConfig, IWlan wlan)
{
this.config = config;
this.clientConfig = clientConfig;
this.wlan = wlan;
if (config.IsCLient)
{
WlanTask();
}
}
public object GetReports(ReportType reportType)
{
return null;
}
public List<string> WlanEnums()
{
return wlan.WlanEnums();
}
public void WlanConnect(WlanSetInfo wlanSetInfo)
{
Task.Run(async () =>
{
foreach (var item in wlanSetInfo.Names)
{
bool res = await wlan.WlanConnect(item);
if (res)
{
clientConfig.Wlan = item;
clientConfig.WlanAuto = wlanSetInfo.Auto;
break;
}
}
});
}
private void WlanTask()
{
Task.Run(async () =>
{
while (true)
{
if (wlan.Connected() == false /*&& string.IsNullOrWhiteSpace(clientConfig.Wlan) == false && clientConfig.WlanAuto*/)
{
var wafis = wlan.WlanEnums();
foreach (var wifi in wafis)
{
bool res = await wlan.WlanConnect(wifi/*clientConfig.Wlan*/);
if (res)
{
break;
}
}
}
await Task.Delay(3000);
}
});
}
}
public sealed class WlanSetInfo
{
public string[] Names { get; set; }
public bool Auto { get; set; }
}
}

View File

@@ -0,0 +1,15 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace cmonitor.client.ruleConfig
{
public interface IRuleConfig
{
public T Get<T>(T defaultValue);
public T Get<T>(string name, T defaultValue);
public void Set<T>(T data);
}
}

View File

@@ -1,8 +1,8 @@
using cmonitor.client.reports.snatch;
using cmonitor.plugins.snatch.report;
using common.libs.database;
using System.ComponentModel.DataAnnotations.Schema;
namespace cmonitor.api
namespace cmonitor.client.ruleConfig
{
[Table("rule")]
@@ -15,12 +15,7 @@ namespace cmonitor.api
this.configDataProvider = configDataProvider;
RuleConfig config = configDataProvider.Load().Result ?? new RuleConfig
{
UserNames = new Dictionary<string, UserNameInfo> { { "snltty", new UserNameInfo {
Rules = new List<RulesInfo>{ new RulesInfo { ID = 1, Name = "默认" } },
Processs = new List<GroupInfo>{ new GroupInfo { ID = 2, Name = "默认" } },
Windows = new List<WindowGroupInfo> { new WindowGroupInfo { ID = 3, Name = "默认" } },
Snatchs = new List<SnatchGroupInfo>{ new SnatchGroupInfo { ID=4, Name="默认" } }
} } }
UserNames = new Dictionary<string, UserNameInfo> { { "snltty", DefaultUser() } }
};
UserNames = config.UserNames;
MaxID = config.MaxID;
@@ -38,6 +33,18 @@ namespace cmonitor.api
}
private readonly object lockObj = new object();
private UserNameInfo DefaultUser()
{
return new UserNameInfo
{
Rules = new List<RulesInfo> { new RulesInfo { ID = 1, Name = "默认" } },
Processs = new List<GroupInfo> { new GroupInfo { ID = 2, Name = "默认" } },
Windows = new List<WindowGroupInfo> { new WindowGroupInfo { ID = 3, Name = "默认" } },
Snatchs = new List<SnatchGroupInfo> { new SnatchGroupInfo { ID = 4, Name = "默认" } },
Modes = "{}",
};
}
public string AddName(string name)
{
@@ -45,12 +52,7 @@ namespace cmonitor.api
{
if (UserNames.ContainsKey(name) == false)
{
UserNames.Add(name, new UserNameInfo
{
Rules = new List<RulesInfo> { new RulesInfo { ID = 1, Name = "默认" } },
Processs = new List<GroupInfo> { new GroupInfo { ID = 1, Name = "默认" } },
Windows = new List<WindowGroupInfo> { new WindowGroupInfo { ID = 1, Name = "默认" } },
});
UserNames.Add(name, DefaultUser());
}
Save();
}
@@ -457,17 +459,26 @@ namespace cmonitor.api
}
return string.Empty;
}
public SnatchItemInfo[] SnatchRandom(int length)
{
return UserNames.Values
.SelectMany(c => c.Snatchs)
.SelectMany(c => c.List).OrderBy(c => Guid.NewGuid())
.Where(c => c.Cate == SnatchCate.Question)
.Where(c => (c.Type == SnatchType.Select && c.Options.Any(c => c.Value)) || (c.Type == SnatchType.Input && string.IsNullOrWhiteSpace(c.Correct) == false))
.Where(c => c.Type == SnatchType.Select && c.Options.Any(c => c.Value) || c.Type == SnatchType.Input && string.IsNullOrWhiteSpace(c.Correct) == false)
.Take(length).ToArray();
}
public string UpdateModes(UpdateModesInfo info)
{
if (UserNames.TryGetValue(info.UserName, out UserNameInfo userNameInfo))
{
userNameInfo.Modes = info.Modes;
}
return string.Empty;
}
public void Save()
{
configDataProvider.Save(this).Wait();
@@ -481,6 +492,8 @@ namespace cmonitor.api
public List<string> Devices { get; set; } = new List<string>();
public List<WindowGroupInfo> Windows { get; set; } = new List<WindowGroupInfo>();
public List<SnatchGroupInfo> Snatchs { get; set; } = new List<SnatchGroupInfo>();
public string Modes { get; set; } = "{}";
}
public sealed class UpdateDevicesInfo
{
@@ -623,8 +636,6 @@ namespace cmonitor.api
public uint GroupID { get; set; }
public uint ID { get; set; }
}
public sealed class SnatchItemInfo
{
public uint ID { get; set; }
@@ -654,4 +665,11 @@ namespace cmonitor.api
public string Text { get; set; }
public bool Value { get; set; }
}
public sealed class UpdateModesInfo
{
public string UserName { get; set; }
public string Modes { get; set; }
}
}

View File

@@ -0,0 +1,75 @@
namespace cmonitor.client.ruleConfig
{
/*
public sealed class RuleConfigJsonFile : IRuleConfig
{
private Dictionary<string, object> cache = new Dictionary<string, object>();
public RuleConfigJsonFile()
{
}
public T Get<T>(T defaultValue)
{
string name = nameof(T);
return Get(name, defaultValue);
}
public T Get<T>(string name, T defaultValue)
{
try
{
if (cache.TryGetValue(name, out object cacheValue))
{
return (T)cacheValue;
}
string value = (Registry.GetValue(savePath, name, string.Empty)).ToString();
if (string.IsNullOrWhiteSpace(value))
{
T data = value.DeJson<T>();
cache[name] = data;
return data;
}
}
catch (Exception)
{
}
return defaultValue;
}
public void Set<T>(T data)
{
try
{
string name = nameof(T);
string value = data.ToJson();
Registry.SetValue(savePath, name, value);
cache[name] = data;
}
catch (Exception)
{
}
}
}
[Table("rule-config")]
public sealed class RuleConfig
{
private readonly IConfigDataProvider<RuleConfig> configDataProvider;
public RuleConfig() { }
public RuleConfig(IConfigDataProvider<RuleConfig> configDataProvider)
{
this.configDataProvider = configDataProvider;
RuleConfig config = configDataProvider.Load().Result ?? new RuleConfig
{
UserNames = new Dictionary<string, string> { { "snltty", "{}" } }
};
UserNames = config.UserNames;
}
public Dictionary<string, string> UserNames { get; set; } = new Dictionary<string, string>();
}*/
}

Some files were not shown because too many files have changed in this diff Show More