diff --git a/XCoder/Common/SpeechRecognition.cs b/XCoder/Common/SpeechRecognition.cs
new file mode 100644
index 0000000..45bc25e
--- /dev/null
+++ b/XCoder/Common/SpeechRecognition.cs
@@ -0,0 +1,185 @@
+using System;
+using System.Collections.Generic;
+using System.Reflection;
+using NewLife.IO;
+using NewLife.Log;
+using NewLife.Model;
+using NewLife.Reflection;
+
+namespace NewLife.Windows
+{
+ /// <summary>语音识别</summary>
+ public class SpeechRecognition : DisposeBase
+ {
+ #region 属性
+ private ISpeech _speech;
+
+ private readonly IDictionary<String, Action> _dic;
+
+ /// <summary>系统名称。用于引导前缀</summary>
+ public String Name { get; set; } = "丁丁";
+
+ /// <summary>最后一次进入引导前缀的时间。</summary>
+ private DateTime _Tip;
+
+ /// <summary>是否可用</summary>
+ public Boolean Enable => _speech != null;
+ #endregion
+
+ #region 构造
+ private SpeechRecognition()
+ {
+ _dic = new Dictionary<String, Action>();
+ }
+
+ /// <summary>销毁</summary>
+ /// <param name="disposing"></param>
+ protected override void Dispose(Boolean disposing)
+ {
+ base.Dispose(disposing);
+
+ _speech.TryDispose();
+ }
+ #endregion
+
+ #region 静态
+ /// <summary>当前实例</summary>
+ public static SpeechRecognition Current { get; } = new SpeechRecognition();
+
+ /// <summary>获取已注册的所有键值</summary>
+ /// <returns></returns>
+ public String[] GetAllKeys() => _dic.Keys.ToArray();
+ #endregion
+
+ #region 方法
+ Boolean Init()
+ {
+ if (_speech != null) return true;
+
+ _speech = ObjectContainer.Current.Resolve<ISpeech>();
+ if (_speech != null) return true;
+
+ try
+ {
+ Assembly.Load("System.Speech, Version=4.0.0.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35");
+
+ var code = Assembly.GetExecutingAssembly().GetFileResource("MySpeech.cs").ToStr();
+ var sc = ScriptEngine.Create(code, false);
+ sc.Compile();
+
+ _speech = sc.Type.CreateInstance() as ISpeech;
+ if (_speech == null) return false;
+
+ if (!_speech.Init()) return false;
+
+ _speech.SpeechRecognized += _rg_SpeechRecognized;
+
+ return true;
+ }
+ catch (Exception ex)
+ {
+ XTrace.WriteException(ex);
+ _speech.TryDispose();
+ return false;
+ }
+ }
+
+ /// <summary>注册要语音识别的关键字到委托</summary>
+ /// <param name="text"></param>
+ /// <param name="callback"></param>
+ public SpeechRecognition Register(String text, Action callback)
+ {
+ var flag = _dic.ContainsKey(text);
+
+ if (callback != null)
+ {
+ _dic[text] = callback;
+
+ if (!flag) Change();
+ }
+ else if (flag)
+ _dic.Remove(text);
+
+ return this;
+ }
+
+ void Change()
+ {
+ if (_speech == null) return;
+
+ lock (this)
+ {
+ if (!Init()) return;
+
+ var list = new List<String>
+ {
+ Name
+ };
+ list.AddRange(_dic.Keys);
+ _speech.SetChoices(list);
+ }
+ }
+
+ //void _rg_SpeechRecognized(object sender, SpeechRecognizedEventArgs e)
+ void _rg_SpeechRecognized(Object sender, RecognitionEventArgs e)
+ {
+ var conf = e.Confidence;
+ if (conf < 0.5) return;
+
+ var txt = e.Text;
+
+ // 语音识别前,必须先识别前缀名称,然后几秒内识别关键字
+ if (_Tip.AddSeconds(3) < DateTime.Now)
+ {
+ // 此时只识别前缀
+ if (txt != Name) return;
+
+ XTrace.WriteLine("语音识别:{0} {1}", txt, conf);
+
+ // 现在可以开始识别关键字啦
+ _Tip = DateTime.Now;
+ }
+ else
+ {
+ XTrace.WriteLine("语音识别:{0} {1}", txt, conf);
+
+ if (_dic.TryGetValue(txt, out var func)) func();
+ }
+ }
+ #endregion
+ }
+
+ /// <summary>语音接口</summary>
+ public interface ISpeech
+ {
+ /// <summary>语音识别事件</summary>
+ event EventHandler<RecognitionEventArgs> SpeechRecognized;
+
+ /// <summary>初始化</summary>
+ /// <returns></returns>
+ Boolean Init();
+
+ /// <summary>设置识别短语</summary>
+ /// <param name="phrases"></param>
+ void SetChoices(IEnumerable<String> phrases);
+ }
+
+ /// <summary>识别事件参数</summary>
+ public class RecognitionEventArgs : EventArgs
+ {
+ /// <summary>获取识别器分配的值,此值表示与给定输入匹配的可能性</summary>
+ public Single Confidence { get; }
+
+ /// <summary>获取语音识别器从识别的输入生成的规范化文本</summary>
+ public String Text { get; }
+
+ /// <summary>实例化</summary>
+ /// <param name="conf"></param>
+ /// <param name="text"></param>
+ public RecognitionEventArgs(Single conf, String text)
+ {
+ Confidence = conf;
+ Text = text;
+ }
+ }
+}
\ No newline at end of file
diff --git a/XCoder/CrazyCoder.csproj b/XCoder/CrazyCoder.csproj
index 6336bab..0dea2f4 100644
--- a/XCoder/CrazyCoder.csproj
+++ b/XCoder/CrazyCoder.csproj
@@ -24,8 +24,11 @@
<ApplicationManifest>Properties\app.manifest</ApplicationManifest>
</PropertyGroup>
<ItemGroup>
+ <Compile Remove="FileEncoding\**" />
<Compile Remove="Protocols\**" />
+ <EmbeddedResource Remove="FileEncoding\**" />
<EmbeddedResource Remove="Protocols\**" />
+ <None Remove="FileEncoding\**" />
<None Remove="Protocols\**" />
</ItemGroup>
<ItemGroup>
@@ -63,27 +66,28 @@
<Content Include="数据库命名规范.txt" />
</ItemGroup>
<ItemGroup>
- <PackageReference Include="NewLife.ModbusRTU" Version="1.1.2022.704" />
+ <PackageReference Include="NewLife.Map" Version="2.0.2022.901" />
+ <PackageReference Include="NewLife.ModbusRTU" Version="1.2.2022.901" />
<PackageReference Include="System.Speech" Version="6.0.0" />
<PackageReference Include="System.Text.Encoding.CodePages" Version="6.0.0" />
<PackageReference Include="Microsoft.VisualBasic" Version="10.3.0" />
<PackageReference Include="NewLife.Core">
- <Version>9.2.2022.701</Version>
+ <Version>10.0.2022.901</Version>
</PackageReference>
<PackageReference Include="NewLife.MQTT">
- <Version>1.0.2022.501</Version>
+ <Version>1.1.2022.901</Version>
</PackageReference>
<PackageReference Include="NewLife.Net">
- <Version>4.1.2022.501</Version>
+ <Version>4.2.2022.901</Version>
</PackageReference>
<PackageReference Include="NewLife.Redis">
- <Version>4.1.2022.701</Version>
+ <Version>5.0.2022.901</Version>
</PackageReference>
<PackageReference Include="NewLife.Stardust">
- <Version>2.2.2022.710</Version>
+ <Version>2.3.2022.901</Version>
</PackageReference>
<PackageReference Include="NewLife.XCode">
- <Version>11.2.2022.701</Version>
+ <Version>11.3.2022.901</Version>
</PackageReference>
<PackageReference Include="SSH.NET">
<Version>2020.0.2</Version>
diff --git a/XCoder/Engine/ModelConfig.cs b/XCoder/Engine/ModelConfig.cs
index c490f1e..a12f7c4 100644
--- a/XCoder/Engine/ModelConfig.cs
+++ b/XCoder/Engine/ModelConfig.cs
@@ -121,9 +121,9 @@ namespace XCoder
[DisplayName("调试")]
public Boolean Debug { get; set; }
- /// <summary> 字典属性</summary>
- [DisplayName("数据字典")]
- public SerializableDictionary<String, String> Items { get; set; } = new SerializableDictionary<String, String>();
+ ///// <summary> 字典属性</summary>
+ //[DisplayName("数据字典")]
+ //public SerializableDictionary<String, String> Items { get; set; } = new SerializableDictionary<String, String>();
#endregion
#region 加载/保存
diff --git a/XCoder/FolderInfo/FrmMain.cs b/XCoder/FolderInfo/FrmMain.cs
index ed9e9c5..428ab28 100644
--- a/XCoder/FolderInfo/FrmMain.cs
+++ b/XCoder/FolderInfo/FrmMain.cs
@@ -94,7 +94,7 @@ namespace XCoder.FolderInfo
{
tn.Nodes.Add("no");
//使用后台线程统计大小信息
- ThreadPoolX.QueueUserWorkItem(() => TongJi(tn));
+ ThreadPool.QueueUserWorkItem(s => TongJi(tn));
}
}
}
diff --git a/XCoder/FrmMDI.cs b/XCoder/FrmMDI.cs
index 88f6d49..aa071de 100644
--- a/XCoder/FrmMDI.cs
+++ b/XCoder/FrmMDI.cs
@@ -43,7 +43,7 @@ namespace XCoder
_load.ContinueWith(t => LoadForms(t.Result));
- ThreadPoolX.QueueUserWorkItem(() => CheckUpdate(true));
+ ThreadPool.QueueUserWorkItem(s => CheckUpdate(true));
}
void LoadForms(Type[] ts)
@@ -170,7 +170,7 @@ namespace XCoder
#region 自动更新
private void 检查更新ToolStripMenuItem_Click(Object sender, EventArgs e)
{
- ThreadPoolX.QueueUserWorkItem(() => CheckUpdate(false));
+ ThreadPool.QueueUserWorkItem(s => CheckUpdate(false));
}
private void CheckUpdate(Boolean auto)
diff --git a/XCoder/Windows/FrmMain.cs b/XCoder/Windows/FrmMain.cs
index 9e13ded..988c627 100644
--- a/XCoder/Windows/FrmMain.cs
+++ b/XCoder/Windows/FrmMain.cs
@@ -222,7 +222,7 @@ namespace XCoder
if (!DAL.ConnStrs.TryGetValue(name, out var connstr) || connstr.IsNullOrWhiteSpace()) return;
// 异步加载
- ThreadPoolX.QueueUserWorkItem(() => { var tables = DAL.Create(name).Tables; });
+ ThreadPool.QueueUserWorkItem(s => { var tables = DAL.Create(name).Tables; });
}
private void btnRefreshTable_Click(Object sender, EventArgs e)
@@ -399,7 +399,7 @@ namespace XCoder
private void oracle客户端运行时检查ToolStripMenuItem1_Click(Object sender, EventArgs e)
{
- ThreadPoolX.QueueUserWorkItem(CheckOracle);
+ ThreadPool.QueueUserWorkItem(s => CheckOracle());
}
void CheckOracle()
{
diff --git a/XCoder/Windows/FrmQuery.cs b/XCoder/Windows/FrmQuery.cs
index 75f483b..c8b5ff2 100644
--- a/XCoder/Windows/FrmQuery.cs
+++ b/XCoder/Windows/FrmQuery.cs
@@ -46,7 +46,7 @@ namespace XCoder
var sql = txtSQL.Text;
if (sql.IsNullOrWhiteSpace()) return;
- ThreadPoolX.QueueUserWorkItem(() =>
+ ThreadPool.QueueUserWorkItem(s =>
{
var sw = Stopwatch.StartNew();
@@ -80,7 +80,7 @@ namespace XCoder
var sql = txtSQL.Text;
if (sql.IsNullOrWhiteSpace()) return;
- ThreadPoolX.QueueUserWorkItem(() =>
+ ThreadPool.QueueUserWorkItem(s =>
{
var sw = Stopwatch.StartNew();
diff --git a/XCoder/Windows/FrmSchema.cs b/XCoder/Windows/FrmSchema.cs
index 9fb4b21..dfb9ff0 100644
--- a/XCoder/Windows/FrmSchema.cs
+++ b/XCoder/Windows/FrmSchema.cs
@@ -42,12 +42,12 @@ namespace XCoder
private void FrmSchema_Load(Object sender, EventArgs e)
{
- ThreadPoolX.QueueUserWorkItem(() =>
+ ThreadPool.QueueUserWorkItem(s =>
{
var tables = Db.CreateMetaData().GetTables();
Invoke(SetList, cbTables, tables);
});
- ThreadPoolX.QueueUserWorkItem(() =>
+ ThreadPool.QueueUserWorkItem(s =>
{
var list = Db.CreateMetaData().MetaDataCollections;
Invoke(SetList, cbSchemas, list);
diff --git a/XCoder/XApi/FrmMain.cs b/XCoder/XApi/FrmMain.cs
index f70a96b..74ddebc 100644
--- a/XCoder/XApi/FrmMain.cs
+++ b/XCoder/XApi/FrmMain.cs
@@ -71,7 +71,7 @@ namespace XApi
LoadConfig();
// 语音识别
- ThreadPoolX.QueueUserWorkItem(() =>
+ ThreadPool.QueueUserWorkItem(s =>
{
var sp = SpeechRecognition.Current;
if (!sp.Enable) return;
diff --git a/XCoder/XCom/FrmMain.cs b/XCoder/XCom/FrmMain.cs
index 6b00356..b835d57 100644
--- a/XCoder/XCom/FrmMain.cs
+++ b/XCoder/XCom/FrmMain.cs
@@ -184,7 +184,7 @@ namespace XCom
return;
}
- ThreadPoolX.QueueUserWorkItem(() =>
+ ThreadPool.QueueUserWorkItem(s =>
{
for (var i = 0; i < count; i++)
{
diff --git a/XCoder/XICO/FileSource.cs b/XCoder/XICO/FileSource.cs
new file mode 100644
index 0000000..95673c1
--- /dev/null
+++ b/XCoder/XICO/FileSource.cs
@@ -0,0 +1,142 @@
+using System;
+using System.Collections.Generic;
+using System.IO;
+using System.Linq;
+using System.Reflection;
+using System.Web;
+
+namespace NewLife.IO
+{
+ /// <summary>文件资源</summary>
+ public static class FileSource
+ {
+ /// <summary>释放文件</summary>
+ /// <param name="asm"></param>
+ /// <param name="fileName"></param>
+ /// <param name="destFile"></param>
+ /// <param name="overWrite"></param>
+ public static void ReleaseFile(this Assembly asm, String fileName, String destFile = null, Boolean overWrite = false)
+ {
+ if (fileName.IsNullOrEmpty()) return;
+
+ if (asm == null) asm = Assembly.GetCallingAssembly();
+ var stream = GetFileResource(asm, fileName);
+ if (stream == null) throw new ArgumentException("filename", $"在程序集{asm.GetName().Name}中无法找到名为{fileName}的资源!");
+
+ if (destFile.IsNullOrEmpty()) destFile = fileName;
+ destFile = destFile.GetFullPath();
+
+ if (File.Exists(destFile) && !overWrite) return;
+
+ //var path = Path.GetDirectoryName(dest);
+ //if (!path.IsNullOrWhiteSpace() && !Directory.Exists(path)) Directory.CreateDirectory(path);
+ destFile.EnsureDirectory(true);
+ try
+ {
+ if (File.Exists(destFile)) File.Delete(destFile);
+
+ using var fs = File.Create(destFile);
+ //IOHelper.CopyTo(stream, fs);
+ stream.CopyTo(fs);
+ }
+ catch { }
+ finally { stream.Dispose(); }
+ }
+
+ /// <summary>释放文件夹</summary>
+ /// <param name="asm"></param>
+ /// <param name="prefix"></param>
+ /// <param name="dest"></param>
+ /// <param name="overWrite"></param>
+ public static void ReleaseFolder(this Assembly asm, String prefix, String dest, Boolean overWrite = false)
+ {
+ if (asm == null) asm = Assembly.GetCallingAssembly();
+ ReleaseFolder(asm, prefix, dest, overWrite, null);
+ }
+
+ /// <summary>释放文件夹</summary>
+ /// <param name="asm"></param>
+ /// <param name="prefix"></param>
+ /// <param name="dest"></param>
+ /// <param name="overWrite"></param>
+ /// <param name="filenameResolver"></param>
+ public static void ReleaseFolder(this Assembly asm, String prefix, String dest, Boolean overWrite = false, Func<String, String> filenameResolver = null)
+ {
+ if (asm == null) asm = Assembly.GetCallingAssembly();
+
+ // 找到符合条件的资源
+ var names = asm.GetManifestResourceNames();
+ if (names == null || names.Length <= 0) return;
+ IEnumerable<String> ns = null;
+ if (prefix.IsNullOrWhiteSpace())
+ ns = names.AsEnumerable();
+ else
+ ns = names.Where(e => e.StartsWithIgnoreCase(prefix));
+
+ if (String.IsNullOrEmpty(dest)) dest = ".".GetFullPath();
+ dest = dest.GetFullPath();
+
+ // 开始处理
+ foreach (var item in ns)
+ {
+ var stream = asm.GetManifestResourceStream(item);
+
+ // 计算filename
+ String filename = null;
+ // 去掉前缀
+ if (filenameResolver != null) filename = filenameResolver(item);
+
+ if (String.IsNullOrEmpty(filename))
+ {
+ filename = item;
+ if (!String.IsNullOrEmpty(prefix)) filename = filename[prefix.Length..];
+ if (filename[0] == '.') filename = filename[1..];
+
+ var ext = Path.GetExtension(item);
+ filename = filename[..^ext.Length];
+ filename = filename.Replace(".", @"\") + ext;
+ filename = Path.Combine(dest, filename);
+ }
+
+ if (File.Exists(filename) && !overWrite) return;
+
+ //var path = Path.GetDirectoryName(filename);
+ //if (!path.IsNullOrWhiteSpace() && !Directory.Exists(path)) Directory.CreateDirectory(path);
+ filename.EnsureDirectory(true);
+ try
+ {
+ if (File.Exists(filename)) File.Delete(filename);
+
+ using var fs = File.Create(filename);
+ //IOHelper.CopyTo(stream, fs);
+ stream.CopyTo(fs);
+ }
+ catch { }
+ finally { stream.Dispose(); }
+ }
+ }
+
+ /// <summary>获取文件资源</summary>
+ /// <param name="asm"></param>
+ /// <param name="filename"></param>
+ /// <returns></returns>
+ public static Stream GetFileResource(this Assembly asm, String filename)
+ {
+ if (String.IsNullOrEmpty(filename)) return null;
+
+ var name = String.Empty;
+ if (asm == null) asm = Assembly.GetCallingAssembly();
+ var ss = asm.GetManifestResourceNames();
+ if (ss != null && ss.Length > 0)
+ {
+ //找到资源名
+ name = ss.FirstOrDefault(e => e == filename);
+ if (String.IsNullOrEmpty(name)) name = ss.FirstOrDefault(e => e.EqualIgnoreCase(filename));
+ if (String.IsNullOrEmpty(name)) name = ss.FirstOrDefault(e => e.EndsWith(filename));
+
+ if (!String.IsNullOrEmpty(name)) return asm.GetManifestResourceStream(name);
+ }
+ return null;
+ }
+ }
+}
\ No newline at end of file
diff --git a/XCoder/XNet/FrmMain.cs b/XCoder/XNet/FrmMain.cs
index 7b1d642..ee61214 100644
--- a/XCoder/XNet/FrmMain.cs
+++ b/XCoder/XNet/FrmMain.cs
@@ -88,7 +88,7 @@ namespace XNet
LoadConfig();
// 语音识别
- ThreadPoolX.QueueUserWorkItem(() =>
+ ThreadPool.QueueUserWorkItem(s =>
{
var sp = SpeechRecognition.Current;
if (!sp.Enable) return;
diff --git a/XCoder/XNet/FrmMqtt.cs b/XCoder/XNet/FrmMqtt.cs
index 3073588..4c0872d 100644
--- a/XCoder/XNet/FrmMqtt.cs
+++ b/XCoder/XNet/FrmMqtt.cs
@@ -68,7 +68,7 @@ namespace XNet
Password = txtPass.Text,
Log = _log,
- LogMessage = true,
+ //LogMessage = true,
};
client.Received += Client_Received;
client.Connected += (s, e) => XTrace.WriteLine("连接成功");