WPF-mvvm学习4 cmd运行与多线程通信
mvvm多线程通信 绑定 执行cmd 相关问题
情景
我想使用cmd调用yara 并实时获取执行结果 由于想要扫描的目录比较大 如果使用阻塞函数可能会被卡死
解决方案1 官方文档
https://docs.microsoft.com/en-us/windows/communitytoolkit/mvvm/observableobject
很好 但是不适合我 似乎cmd在运行时等待输入会自动阻塞)
但是执行别的异步函数没问题
关于该解决方案的一个demo
private TaskNotifier<int> _count;
/// <summary>
/// 任务属性绑定
/// </summary>
public Task<int> Count
{
get => _count;
set => SetPropertyAndNotifyOnCompletion(ref _count, value);
}
public ICommand RequestValueCmd { get; set; }
private async void RequestValue()
{
await Task.Delay(5000);
Count = Task.Run(() =>
{
return 50;
});
}
<TextBlock Text="{Binding Count.Result, UpdateSourceTrigger=PropertyChanged}" />
<Button
Command="{Binding RequestValueCmd}"
Content="延时绑定" />
解决方案2
https://blog.csdn.net/fangyu723/article/details/118783975
使用他封装好的类
namespace CmdNameSpace
{
public class Command
{
private const int _ReadSize = 1024;
private Process _CMD;//cmd进程
private Encoding _OutEncoding;//输出字符编码
private Stream _OutStream;//基础输出流
private Stream _ErrorStream;//错误输出流
public event Action<string> Output;//输出事件
public event Action<string> Error;//错误事件
public event Action Exited;//退出事件
private bool _Run;//循环控制
private byte[] _TempBuffer;//临时缓冲
private byte[] _ReadBuffer;//读取缓存区
private byte[] _ETempBuffer;//临时缓冲
private byte[] _ErrorBuffer;//错误读取缓存区
public Command()
{
_CMD = new Process();
_CMD.StartInfo.FileName = "cmd.exe";
_CMD.StartInfo.UseShellExecute = false;//是否使用操作系统shell启动
_CMD.StartInfo.RedirectStandardInput = true;//接受来自调用程序的输入信息
_CMD.StartInfo.RedirectStandardOutput = true;//由调用程序获取输出信息
_CMD.StartInfo.RedirectStandardError = true;//重定向标准错误输出
_CMD.StartInfo.CreateNoWindow = true;//不显示程序窗口
_CMD.Exited += _CMD_Exited;
_ReadBuffer = new byte[_ReadSize];
_ErrorBuffer = new byte[_ReadSize];
ReStart();
}
/// <summary>
/// 停止使用,关闭进程和循环线程
/// </summary>
public void Stop()
{
_Run = false;
_CMD.Close();
}
/// <summary>
/// 重新启用
/// </summary>
public void ReStart()
{
Stop();
_CMD.Start();
_OutEncoding = _CMD.StandardOutput.CurrentEncoding;
_OutStream = _CMD.StandardOutput.BaseStream;
_ErrorStream = _CMD.StandardError.BaseStream;
_Run = true;
_CMD.StandardInput.AutoFlush = true;
ReadResult();
ErrorResult();
}
//退出事件
private void _CMD_Exited(object sender , EventArgs e)
{
Exited?.Invoke();
}
/// <summary>
/// 执行cmd命令
/// </summary>
/// <param name="cmd">需要执行的命令</param>
public void RunCMD(string cmd)
{
if (!_Run)
{
if (cmd.Trim().Equals("/restart" , StringComparison.CurrentCultureIgnoreCase))
{
ReStart();
}
return;
}
if (_CMD.HasExited)
{
Stop();
return;
}
_CMD.StandardInput.WriteLine(cmd);
}
//异步读取输出结果
private void ReadResult()
{
if (!_Run)
{
return;
}
_OutStream.BeginRead(_ReadBuffer , 0 , _ReadSize , ReadEnd , null);
}
//一次异步读取结束
private void ReadEnd(IAsyncResult ar)
{
int count = _OutStream.EndRead(ar);
if (count < 1)
{
if (_CMD.HasExited)
{
Stop();
}
return;
}
if (_TempBuffer == null)
{
_TempBuffer = new byte[count];
Buffer.BlockCopy(_ReadBuffer , 0 , _TempBuffer , 0 , count);
}
else
{
byte[] buff = _TempBuffer;
_TempBuffer = new byte[buff.Length + count];
Buffer.BlockCopy(buff , 0 , _TempBuffer , 0 , buff.Length);
Buffer.BlockCopy(_ReadBuffer , 0 , _TempBuffer , buff.Length , count);
}
if (count < _ReadSize)
{
string str = _OutEncoding.GetString(_TempBuffer);
Output?.Invoke(str);
_TempBuffer = null;
}
ReadResult();
}
//异步读取错误输出
private void ErrorResult()
{
if (!_Run)
{
return;
}
_ErrorStream.BeginRead(_ErrorBuffer , 0 , _ReadSize , ErrorCallback , null);
}
private void ErrorCallback(IAsyncResult ar)
{
int count = _ErrorStream.EndRead(ar);
if (count < 1)
{
if (_CMD.HasExited)
{
Stop();
}
return;
}
if (_ETempBuffer == null)
{
_ETempBuffer = new byte[count];
Buffer.BlockCopy(_ErrorBuffer , 0 , _ETempBuffer , 0 , count);
}
else
{
byte[] buff = _ETempBuffer;
_ETempBuffer = new byte[buff.Length + count];
Buffer.BlockCopy(buff , 0 , _ETempBuffer , 0 , buff.Length);
Buffer.BlockCopy(_ErrorBuffer , 0 , _ETempBuffer , buff.Length , count);
}
if (count < _ReadSize)
{
string str = _OutEncoding.GetString(_ETempBuffer);
Error?.Invoke(str);
_ETempBuffer = null;
}
ErrorResult();
}
~Command()
{
_Run = false;
_CMD?.Close();
_CMD?.Dispose();
}
}
}
调用
private async void ScanSingleFileExecute()
{
fppath.Info = "";
Command command = new Command();
command.Output += Command_Output;
//用Task避免发送命令太多堵塞
_ = Task.Run(() =>
{
for (int i = 0 ; i < fppath.RuleList.Count ; i++)
{
string cmdString = currentpath + "\\yara\\yara64.exe " + fppath.RuleList[i] + " " + fppath.FilePath + " -r";
// string cmdString = "ipconfig";
command.RunCMD(cmdString);
}
});
}
private void Command_Output(string msg)
{ //或者对msg做些处理啥的再加
fppath.test += msg;
}
<TextBox
Grid.Row="2"
Grid.Column="0"
Margin="0,0,0,0"
Text="{Binding fppath.test, Mode=OneWay, UpdateSourceTrigger=PropertyChanged}" />
这样就实现了绑定到xaml 并实时更新返回值
MVVM 跨线程更改数据源
ThreadPool.QueueUserWorkItem(delegate
{
System.Threading.SynchronizationContext.SetSynchronizationContext(new
System.Windows.Threading.DispatcherSynchronizationContext(System.Windows.Application.Current.Dispatcher));
System.Threading.SynchronizationContext.Current.Post(p1 =>
{
//代码
} , null);
});
yara
yara是病毒匹配工具
先上help
YARA 4.2.0, the pattern matching swiss army knife.
Usage: yara [OPTION]... [NAMESPACE:]RULES_FILE... FILE | DIR | PID
Mandatory arguments to long options are mandatory for short options too.
--atom-quality-table=FILE path to a file with the atom quality table
-C, --compiled-rules load compiled rules
-c, --count print only number of matches
-d, --define=VAR=VALUE define external variable
--fail-on-warnings fail on warnings
-f, --fast-scan fast matching mode
-h, --help show this help and exit
-i, --identifier=IDENTIFIER print only rules named IDENTIFIER
--max-process-memory-chunk=NUMBER set maximum chunk size while reading process memory (default=1073741824)
-l, --max-rules=NUMBER abort scanning after matching a NUMBER of rules
--max-strings-per-rule=NUMBER set maximum number of strings per rule (default=10000)
-x, --module-data=MODULE=FILE pass FILE's content as extra data to MODULE
-n, --negate print only not satisfied rules (negate)
-N, --no-follow-symlinks do not follow symlinks when scanning
-w, --no-warnings disable warnings
-m, --print-meta print metadata
-D, --print-module-data print module data
-e, --print-namespace print rules' namespace
-S, --print-stats print rules' statistics
-s, --print-strings print matching strings
-L, --print-string-length print length of matched strings
-g, --print-tags print tags
-r, --recursive recursively search directories
--scan-list scan files listed in FILE, one per line
-z, --skip-larger=NUMBER skip files larger than the given size when scanning a directory
-k, --stack-size=SLOTS set maximum stack size (default=16384)
-t, --tag=TAG print only rules tagged as TAG
-p, --threads=NUMBER use the specified NUMBER of threads to scan a directory
-a, --timeout=SECONDS abort scanning after the given number of SECONDS
-v, --version show version information
Send bug reports and suggestions to: vmalvarez@virustotal.com.
简单使用yara yourrules.yar testfile
来检测
使用yarac yourrule compilerule
来编译规则以加快检测速度