<?xml version="1.0" encoding="utf-8"?><rss xmlns:dc="http://purl.org/dc/elements/1.1/" version="2.0"><channel><title>好记性不如烂笔头</title><link>http://51scm.net/</link><description>Good Luck To You!</description><item><title>[教程]QJSON 4.0 与 3.0 功能特性对比</title><link>http://51scm.net/?id=9</link><description>&lt;p style=&quot;box-sizing: inherit; border: 0px; margin: 0px auto 1.6em; outline: 0px; padding: 0px; vertical-align: baseline; max-width: var(--wp--custom--ast-content-width-size); color: rgb(57, 60, 64); font-family: -apple-system, BlinkMacSystemFont, &amp;quot;Segoe UI&amp;quot;, Roboto, Oxygen-Sans, Ubuntu, Cantarell, &amp;quot;Helvetica Neue&amp;quot;, sans-serif; text-wrap-mode: wrap; background-color: rgb(255, 255, 255);&quot;&gt;QJSON 4.0 目录已经处于基本可用状态，可以供大家在新的开发项目中试用，就目前版本来说，4.0 相比 3.0 版有以下大不同：&lt;/p&gt;&lt;ol class=&quot;wp-block-list list-paddingleft-2&quot; style=&quot;box-sizing: border-box; border: 0px; margin-top: revert; margin-right: auto; margin-bottom: revert; margin-left: auto; outline: 0px; padding-top: revert; padding-right: revert; padding-bottom: revert; padding-left: 20px; vertical-align: baseline; list-style-position: initial; list-style-image: initial; max-width: var(--wp--custom--ast-content-width-size); color: rgb(57, 60, 64); font-family: -apple-system, BlinkMacSystemFont, &amp;quot;Segoe UI&amp;quot;, Roboto, Oxygen-Sans, Ubuntu, Cantarell, &amp;quot;Helvetica Neue&amp;quot;, sans-serif; text-wrap-mode: wrap; background-color: rgb(255, 255, 255);&quot;&gt;&lt;li&gt;&lt;p&gt;&lt;span style=&quot;box-sizing: inherit; font-weight: 700;&quot;&gt;架构变化&lt;/span&gt;&lt;/p&gt;&lt;/li&gt;&lt;ul class=&quot;wp-block-list list-paddingleft-2&quot; style=&quot;list-style-type: disc;&quot;&gt;&lt;li&gt;&lt;p&gt;3.0 版 TQJson 是一个类 (class)，4.0 版是一个记录类型 (record) 并且改名为 TQJsonNode 以避免和 3.0 版本冲突&lt;/p&gt;&lt;/li&gt;&lt;li&gt;&lt;p&gt;4.0 版实现了 IQSerializeReader 和 IQSerializeWriter 接口，可以统一多种格式的序列化和反序列化&lt;/p&gt;&lt;/li&gt;&lt;li&gt;&lt;p&gt;4.0 版将支持 Free Pascal 3.3.1 + 版本，3.0 版本不支持&lt;/p&gt;&lt;/li&gt;&lt;/ul&gt;&lt;li&gt;&lt;p&gt;&lt;span style=&quot;box-sizing: inherit; font-weight: 700;&quot;&gt;内存管理&lt;/span&gt;&lt;/p&gt;&lt;/li&gt;&lt;ul class=&quot;wp-block-list list-paddingleft-2&quot; style=&quot;list-style-type: disc;&quot;&gt;&lt;li&gt;&lt;p&gt;4.0 支持字符串缓存模式，重复的字符串内容，只会保存一个版本&lt;/p&gt;&lt;/li&gt;&lt;li&gt;&lt;p&gt;4.0 使用双向链表而不是数组来存储同级的兄弟结点，分配内存次数相比数组模式更少&lt;/p&gt;&lt;/li&gt;&lt;li&gt;&lt;p&gt;4.0 支持按数组方式访问，但如果你不使用，它永远不会分配数据索引，从而节省开销&lt;/p&gt;&lt;/li&gt;&lt;li&gt;&lt;p&gt;4.0 对序列化进行了专门的优化，从流中加载大 JSON 和将 JSON 数据保存到流都会节省很多内存&lt;/p&gt;&lt;/li&gt;&lt;li&gt;&lt;p&gt;4.0 通过支持缓存模式和只进模式，可以大幅节省内存占用和分配次数&lt;/p&gt;&lt;/li&gt;&lt;li&gt;&lt;p&gt;总体来说，4.0 在保证性能的前提下，对内存使用情况更克制，算法也更复杂一些。&lt;/p&gt;&lt;/li&gt;&lt;/ul&gt;&lt;li&gt;&lt;p&gt;&lt;span style=&quot;box-sizing: inherit; font-weight: 700;&quot;&gt;性能变化&lt;/span&gt;&lt;/p&gt;&lt;/li&gt;&lt;ul class=&quot;wp-block-list list-paddingleft-2&quot; style=&quot;list-style-type: disc;&quot;&gt;&lt;li&gt;&lt;p&gt;使用 TQSerializer 进行基于 RTTI 的序列化和反序列化（推荐，接口统一，更易拓展）&lt;/p&gt;&lt;/li&gt;&lt;li&gt;&lt;p&gt;基于 TQJsonEncoder/TQJsonParser 来执行序列化或反序列化（内存占用更小&lt;/p&gt;&lt;/li&gt;&lt;li&gt;&lt;p&gt;对于遍历的场景，4.0 因为使用双向链接表，ForEach 或直接通过 FirstChild-&amp;gt;LastChild 遍历都很方便，理论性能和 3.0 一致&lt;/p&gt;&lt;/li&gt;&lt;li&gt;&lt;p&gt;对于随机只读场景，4.0 因为在首次随机访问时会缓存索引，纯随机读取场景要稍差一点，但也只限于首次访问，后续访问性能没有差距。&lt;/p&gt;&lt;/li&gt;&lt;li&gt;&lt;p&gt;对于追加数据场景，4.0 因为增加链表元素分配一次内存，相比数组方式可能要调整数据大小，理论上要更快一些&lt;/p&gt;&lt;/li&gt;&lt;li&gt;&lt;p&gt;对于解析场景，4.0 因为新的架构和解析算法，理论性能比 3.0 有了较大的提升&lt;/p&gt;&lt;/li&gt;&lt;li&gt;&lt;p&gt;对于序列化场景，4.0 实现了新的工作流程，减少了内存的重复分配和释放，在性能上也有了很大的提升。与 3.0 相比，也提供了更多的序列化方式：&lt;/p&gt;&lt;/li&gt;&lt;/ul&gt;&lt;li&gt;&lt;p&gt;&lt;span style=&quot;box-sizing: inherit; font-weight: 700;&quot;&gt;学习难度&lt;/span&gt;&lt;/p&gt;&lt;/li&gt;&lt;ul class=&quot;wp-block-list list-paddingleft-2&quot; style=&quot;list-style-type: disc;&quot;&gt;&lt;li&gt;&lt;p&gt;4.0 统一了 JSON/XML/MessagePack 等格式序列化接口，提供了 TQSerializer 来统一格式的序列化和反序列化，方便用户将来能够快速的支持多种格式输出。&lt;/p&gt;&lt;/li&gt;&lt;li&gt;&lt;p&gt;4.0 公开接口和 3.0 基本保持一致，迁移成本不高。但因为 4.0 从类转为记录类型，所以相对来说 ，还是要用户不可避免的在代码层级做一些变动，但学习难度几乎没有。&lt;/p&gt;&lt;/li&gt;&lt;/ul&gt;&lt;li&gt;&lt;p&gt;&lt;span style=&quot;box-sizing: inherit; font-weight: 700;&quot;&gt;其它变化&lt;/span&gt;&lt;/p&gt;&lt;/li&gt;&lt;ul class=&quot;wp-block-list list-paddingleft-2&quot; style=&quot;list-style-type: disc;&quot;&gt;&lt;li&gt;&lt;p&gt;4.0 完整支持注释类型（jdtLineComment / jdtBlockComment)，而 3.0 无论解码还是编码，都会忽略注释&lt;/p&gt;&lt;/li&gt;&lt;li&gt;&lt;p&gt;4.0 用户可以通过回调来控制解析流程，跳过不需要解析的结点，从而提升效率&lt;/p&gt;&lt;/li&gt;&lt;li&gt;&lt;p&gt;4.0 编码设置增加了额外的选项来更灵活的控制输出 JSON 的方式，比如日期时间类型输出为 Unix 时间戳。&lt;/p&gt;&lt;/li&gt;&lt;li&gt;&lt;p&gt;更多变动，请阅读源码了解。&lt;/p&gt;&lt;/li&gt;&lt;/ul&gt;&lt;/ol&gt;&lt;p&gt;&lt;br/&gt;&lt;/p&gt;</description><pubDate>Sat, 08 Mar 2025 16:47:13 +0800</pubDate></item><item><title>QPlugins 插件引擎教程 – 让 QPlugins 协助你解耦程序</title><link>http://51scm.net/?id=8</link><description>&lt;p style=&quot;line-height: 1.7; margin-top: -0.3em; margin-bottom: 1em; color: rgb(51, 51, 51); font-family: &amp;quot;Lucida Grande&amp;quot;, &amp;quot;Helvetica Neue&amp;quot;, Helvetica, Arial, Verdana, &amp;quot;PingFang SC&amp;quot;, &amp;quot;Hiragino Sans GB&amp;quot;, STHeiti, &amp;quot;Microsoft YaHei&amp;quot;, &amp;quot;WenQuanYi Micro Hei&amp;quot;, &amp;quot;WenQuanYi Micro Hei Mono&amp;quot;, &amp;quot;WenQuanYi Zen Hei&amp;quot;, &amp;quot;WenQuanYi Zen Hei Mono&amp;quot;, &amp;quot;Noto Sans CJK SC&amp;quot;, &amp;quot;Source Han Sans CN&amp;quot;, SimSun, sans-serif; text-wrap-mode: wrap; background-color: rgb(255, 255, 255);&quot;&gt;程序就是一堆面条，理顺了，好用又好看，如果缠在一起，那就会煮成一坨面疙瘩了。QPlugins 虽然是一个插件引擎，但是记住我们的理念，插件即服务，服务也就是插件一种插接方式。&lt;/p&gt;&lt;p style=&quot;line-height: 1.7; margin-top: 0px; margin-bottom: 1em; color: rgb(51, 51, 51); font-family: &amp;quot;Lucida Grande&amp;quot;, &amp;quot;Helvetica Neue&amp;quot;, Helvetica, Arial, Verdana, &amp;quot;PingFang SC&amp;quot;, &amp;quot;Hiragino Sans GB&amp;quot;, STHeiti, &amp;quot;Microsoft YaHei&amp;quot;, &amp;quot;WenQuanYi Micro Hei&amp;quot;, &amp;quot;WenQuanYi Micro Hei Mono&amp;quot;, &amp;quot;WenQuanYi Zen Hei&amp;quot;, &amp;quot;WenQuanYi Zen Hei Mono&amp;quot;, &amp;quot;Noto Sans CJK SC&amp;quot;, &amp;quot;Source Han Sans CN&amp;quot;, SimSun, sans-serif; text-wrap-mode: wrap; background-color: rgb(255, 255, 255);&quot;&gt;首先，我们了解的第一个基于 QPlugins 的 Demo 位于 DockForms 里的 InProcess 目录下。它的目标是将不同单元的窗体嵌入到主窗体的 TPageControl 的不同页面中，而不需要引用主窗体的任何东西。&lt;/p&gt;&lt;p style=&quot;line-height: 1.7; margin-top: 0px; margin-bottom: 1em; color: rgb(51, 51, 51); font-family: &amp;quot;Lucida Grande&amp;quot;, &amp;quot;Helvetica Neue&amp;quot;, Helvetica, Arial, Verdana, &amp;quot;PingFang SC&amp;quot;, &amp;quot;Hiragino Sans GB&amp;quot;, STHeiti, &amp;quot;Microsoft YaHei&amp;quot;, &amp;quot;WenQuanYi Micro Hei&amp;quot;, &amp;quot;WenQuanYi Micro Hei Mono&amp;quot;, &amp;quot;WenQuanYi Zen Hei&amp;quot;, &amp;quot;WenQuanYi Zen Hei Mono&amp;quot;, &amp;quot;Noto Sans CJK SC&amp;quot;, &amp;quot;Source Han Sans CN&amp;quot;, SimSun, sans-serif; text-wrap-mode: wrap; background-color: rgb(255, 255, 255);&quot;&gt;使用 QPlugins 插件引擎所要做的第一件事：确定服务的接口方式。&lt;/p&gt;&lt;p style=&quot;line-height: 1.7; margin-top: 0px; margin-bottom: 1em; color: rgb(51, 51, 51); font-family: &amp;quot;Lucida Grande&amp;quot;, &amp;quot;Helvetica Neue&amp;quot;, Helvetica, Arial, Verdana, &amp;quot;PingFang SC&amp;quot;, &amp;quot;Hiragino Sans GB&amp;quot;, STHeiti, &amp;quot;Microsoft YaHei&amp;quot;, &amp;quot;WenQuanYi Micro Hei&amp;quot;, &amp;quot;WenQuanYi Micro Hei Mono&amp;quot;, &amp;quot;WenQuanYi Zen Hei&amp;quot;, &amp;quot;WenQuanYi Zen Hei Mono&amp;quot;, &amp;quot;Noto Sans CJK SC&amp;quot;, &amp;quot;Source Han Sans CN&amp;quot;, SimSun, sans-serif; text-wrap-mode: wrap; background-color: rgb(255, 255, 255);&quot;&gt;如在&amp;nbsp;&lt;a href=&quot;https://blog.qdac.cc/?p=2781&quot; target=&quot;_blank&quot; style=&quot;text-decoration-line: none; color: rgb(22, 160, 133); transition: color 0.2s;&quot;&gt;了解 QPlugins 的整体架构&lt;/a&gt;&amp;nbsp;一节中所说的，我们通过 IQPluginsManager 接口来管理一切服务和通知，而每个插件或主程序本身提供一个或多个服务。而服务的调用者与服务之间要如何交互呢？这是在将 QPlugins 插件引擎引入到你程序时，需要考虑的第一个问题：&lt;/p&gt;&lt;ul style=&quot;box-sizing: border-box; color: rgb(51, 51, 51); font-family: &amp;quot;Lucida Grande&amp;quot;, &amp;quot;Helvetica Neue&amp;quot;, Helvetica, Arial, Verdana, &amp;quot;PingFang SC&amp;quot;, &amp;quot;Hiragino Sans GB&amp;quot;, STHeiti, &amp;quot;Microsoft YaHei&amp;quot;, &amp;quot;WenQuanYi Micro Hei&amp;quot;, &amp;quot;WenQuanYi Micro Hei Mono&amp;quot;, &amp;quot;WenQuanYi Zen Hei&amp;quot;, &amp;quot;WenQuanYi Zen Hei Mono&amp;quot;, &amp;quot;Noto Sans CJK SC&amp;quot;, &amp;quot;Source Han Sans CN&amp;quot;, SimSun, sans-serif; text-wrap-mode: wrap; background-color: rgb(255, 255, 255);&quot; class=&quot; list-paddingleft-2&quot;&gt;&lt;li&gt;&lt;p&gt;使用一个 Interface 接口定义&lt;br/&gt;此方式的优点是参数形式统一明确，而且参数类型一般是系统提供的内置类型，效率较高，调用时与传统习惯比较一致。&lt;/p&gt;&lt;/li&gt;&lt;li&gt;&lt;p&gt;使用 IQService 的 Execute 函数来执行&lt;br/&gt;此方式的优点是不需要预先定义接口，但仍然要知道需要传递的参数的类型。此类调用通过 IQParams 接口来将参数传递给服务的提供者，而服务的提供者通过 IQParams 来得到相关的参数数据，并执行服务。在本示例中，我们使用将演示这一用法。&lt;/p&gt;&lt;/li&gt;&lt;/ul&gt;&lt;p style=&quot;line-height: 1.7; margin-top: 0px; margin-bottom: 1em; color: rgb(51, 51, 51); font-family: &amp;quot;Lucida Grande&amp;quot;, &amp;quot;Helvetica Neue&amp;quot;, Helvetica, Arial, Verdana, &amp;quot;PingFang SC&amp;quot;, &amp;quot;Hiragino Sans GB&amp;quot;, STHeiti, &amp;quot;Microsoft YaHei&amp;quot;, &amp;quot;WenQuanYi Micro Hei&amp;quot;, &amp;quot;WenQuanYi Micro Hei Mono&amp;quot;, &amp;quot;WenQuanYi Zen Hei&amp;quot;, &amp;quot;WenQuanYi Zen Hei Mono&amp;quot;, &amp;quot;Noto Sans CJK SC&amp;quot;, &amp;quot;Source Han Sans CN&amp;quot;, SimSun, sans-serif; text-wrap-mode: wrap; background-color: rgb(255, 255, 255);&quot;&gt;好了，由于本示例使用的第二种方式来调用，也就是说，我们不知道提供服务接口的GUID编码，那么我们就需要知道怎么找到这个服务。QPlugins 提供了一个 ByPath 函数来让我们通过路径来查找服务。我们来看 ByPath 的声明：&lt;/p&gt;&lt;pre class=&quot;lang:delphi decode:true&quot; style=&quot;font-family: Monaco, Menlo, Consolas, Inconsolata, &amp;quot;Deja Vu Sans Mono&amp;quot;, &amp;quot;Droid Sans Mono&amp;quot;, &amp;quot;Lucida Console&amp;quot;, &amp;quot;Courier New&amp;quot;, Courier, monospace; text-wrap-mode: wrap; overflow-wrap: break-word; padding: 2em; background-color: rgb(247, 247, 247); color: rgb(51, 51, 51);&quot;&gt;function&amp;nbsp;ByPath(APath:&amp;nbsp;PWideChar):&amp;nbsp;IQService;&amp;nbsp;stdcall;&lt;/pre&gt;&lt;p style=&quot;line-height: 1.7; margin-top: 0px; margin-bottom: 1em; color: rgb(51, 51, 51); font-family: &amp;quot;Lucida Grande&amp;quot;, &amp;quot;Helvetica Neue&amp;quot;, Helvetica, Arial, Verdana, &amp;quot;PingFang SC&amp;quot;, &amp;quot;Hiragino Sans GB&amp;quot;, STHeiti, &amp;quot;Microsoft YaHei&amp;quot;, &amp;quot;WenQuanYi Micro Hei&amp;quot;, &amp;quot;WenQuanYi Micro Hei Mono&amp;quot;, &amp;quot;WenQuanYi Zen Hei&amp;quot;, &amp;quot;WenQuanYi Zen Hei Mono&amp;quot;, &amp;quot;Noto Sans CJK SC&amp;quot;, &amp;quot;Source Han Sans CN&amp;quot;, SimSun, sans-serif; text-wrap-mode: wrap; background-color: rgb(255, 255, 255);&quot;&gt;实际上，这个函数是由 IQServices 接口规定的，APath 约定了服务提供路径，如本示例中的 “Services/Docks”。&lt;/p&gt;&lt;p style=&quot;line-height: 1.7; margin-top: 0px; margin-bottom: 1em; color: rgb(51, 51, 51); font-family: &amp;quot;Lucida Grande&amp;quot;, &amp;quot;Helvetica Neue&amp;quot;, Helvetica, Arial, Verdana, &amp;quot;PingFang SC&amp;quot;, &amp;quot;Hiragino Sans GB&amp;quot;, STHeiti, &amp;quot;Microsoft YaHei&amp;quot;, &amp;quot;WenQuanYi Micro Hei&amp;quot;, &amp;quot;WenQuanYi Micro Hei Mono&amp;quot;, &amp;quot;WenQuanYi Zen Hei&amp;quot;, &amp;quot;WenQuanYi Zen Hei Mono&amp;quot;, &amp;quot;Noto Sans CJK SC&amp;quot;, &amp;quot;Source Han Sans CN&amp;quot;, SimSun, sans-serif; text-wrap-mode: wrap; background-color: rgb(255, 255, 255);&quot;&gt;为了更好的说明这一点，我们来看我们示例中的代码：&lt;/p&gt;&lt;pre class=&quot;lang:delphi decode:true&quot; style=&quot;font-family: Monaco, Menlo, Consolas, Inconsolata, &amp;quot;Deja Vu Sans Mono&amp;quot;, &amp;quot;Droid Sans Mono&amp;quot;, &amp;quot;Lucida Console&amp;quot;, &amp;quot;Courier New&amp;quot;, Courier, monospace; text-wrap-mode: wrap; overflow-wrap: break-word; padding: 2em; background-color: rgb(247, 247, 247); color: rgb(51, 51, 51);&quot;&gt;procedure&amp;nbsp;TForm1.FormCreate(Sender:&amp;nbsp;TObject);
var
&amp;nbsp;&amp;nbsp;ARoot:&amp;nbsp;IQServices;
&amp;nbsp;&amp;nbsp;I:&amp;nbsp;Integer;
&amp;nbsp;&amp;nbsp;ATabSheet:&amp;nbsp;TTabSheet;
&amp;nbsp;&amp;nbsp;AParams:&amp;nbsp;IQParams;
begin
&amp;nbsp;&amp;nbsp;ARoot&amp;nbsp;:=&amp;nbsp;PluginsManager.ByPath(&amp;#39;Services/Docks&amp;#39;)&amp;nbsp;as&amp;nbsp;IQServices;
&amp;nbsp;&amp;nbsp;if&amp;nbsp;Assigned(ARoot)&amp;nbsp;then
&amp;nbsp;&amp;nbsp;begin
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;AParams&amp;nbsp;:=&amp;nbsp;TQParams.Create;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;AParams.Add(&amp;#39;Parent&amp;#39;,&amp;nbsp;ptUInt64);
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;for&amp;nbsp;I&amp;nbsp;:=&amp;nbsp;0&amp;nbsp;to&amp;nbsp;ARoot.Count&amp;nbsp;-&amp;nbsp;1&amp;nbsp;do
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;begin
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;ATabSheet&amp;nbsp;:=&amp;nbsp;TTabSheet.Create(PageControl1);
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;ATabSheet.PageControl&amp;nbsp;:=&amp;nbsp;PageControl1;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;ATabSheet.Caption&amp;nbsp;:=&amp;nbsp;ARoot[I].Name;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;AParams[0].AsInt64&amp;nbsp;:=&amp;nbsp;IntPtr(ATabSheet);
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;ARoot[I].Execute(AParams,&amp;nbsp;nil);
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;end;
&amp;nbsp;&amp;nbsp;end;
end;&lt;/pre&gt;&lt;p style=&quot;line-height: 1.7; margin-top: 0px; margin-bottom: 1em; color: rgb(51, 51, 51); font-family: &amp;quot;Lucida Grande&amp;quot;, &amp;quot;Helvetica Neue&amp;quot;, Helvetica, Arial, Verdana, &amp;quot;PingFang SC&amp;quot;, &amp;quot;Hiragino Sans GB&amp;quot;, STHeiti, &amp;quot;Microsoft YaHei&amp;quot;, &amp;quot;WenQuanYi Micro Hei&amp;quot;, &amp;quot;WenQuanYi Micro Hei Mono&amp;quot;, &amp;quot;WenQuanYi Zen Hei&amp;quot;, &amp;quot;WenQuanYi Zen Hei Mono&amp;quot;, &amp;quot;Noto Sans CJK SC&amp;quot;, &amp;quot;Source Han Sans CN&amp;quot;, SimSun, sans-serif; text-wrap-mode: wrap; background-color: rgb(255, 255, 255);&quot;&gt;首先，在继续之前，我们了解下这里的一个约定，所有要嵌入的子窗体必需将自己注册到 “Services/Docks” 服务列表（IQServices）结点下，做为子服务，以便主程序进行调用。&lt;/p&gt;&lt;p style=&quot;line-height: 1.7; margin-top: 0px; margin-bottom: 1em; color: rgb(51, 51, 51); font-family: &amp;quot;Lucida Grande&amp;quot;, &amp;quot;Helvetica Neue&amp;quot;, Helvetica, Arial, Verdana, &amp;quot;PingFang SC&amp;quot;, &amp;quot;Hiragino Sans GB&amp;quot;, STHeiti, &amp;quot;Microsoft YaHei&amp;quot;, &amp;quot;WenQuanYi Micro Hei&amp;quot;, &amp;quot;WenQuanYi Micro Hei Mono&amp;quot;, &amp;quot;WenQuanYi Zen Hei&amp;quot;, &amp;quot;WenQuanYi Zen Hei Mono&amp;quot;, &amp;quot;Noto Sans CJK SC&amp;quot;, &amp;quot;Source Han Sans CN&amp;quot;, SimSun, sans-serif; text-wrap-mode: wrap; background-color: rgb(255, 255, 255);&quot;&gt;接下来，各个子窗体的实现单元，自己在 initialization 单元中，通过 RegisterService 将自己注册到 PluginsManager 的 “Service/Docks”下面，做为一个子服务。&lt;/p&gt;&lt;p style=&quot;line-height: 1.7; margin-top: 0px; margin-bottom: 1em; color: rgb(51, 51, 51); font-family: &amp;quot;Lucida Grande&amp;quot;, &amp;quot;Helvetica Neue&amp;quot;, Helvetica, Arial, Verdana, &amp;quot;PingFang SC&amp;quot;, &amp;quot;Hiragino Sans GB&amp;quot;, STHeiti, &amp;quot;Microsoft YaHei&amp;quot;, &amp;quot;WenQuanYi Micro Hei&amp;quot;, &amp;quot;WenQuanYi Micro Hei Mono&amp;quot;, &amp;quot;WenQuanYi Zen Hei&amp;quot;, &amp;quot;WenQuanYi Zen Hei Mono&amp;quot;, &amp;quot;Noto Sans CJK SC&amp;quot;, &amp;quot;Source Han Sans CN&amp;quot;, SimSun, sans-serif; text-wrap-mode: wrap; background-color: rgb(255, 255, 255);&quot;&gt;好了，现在我们来看上面的代码做了什么：&lt;/p&gt;&lt;ul style=&quot;box-sizing: border-box; color: rgb(51, 51, 51); font-family: &amp;quot;Lucida Grande&amp;quot;, &amp;quot;Helvetica Neue&amp;quot;, Helvetica, Arial, Verdana, &amp;quot;PingFang SC&amp;quot;, &amp;quot;Hiragino Sans GB&amp;quot;, STHeiti, &amp;quot;Microsoft YaHei&amp;quot;, &amp;quot;WenQuanYi Micro Hei&amp;quot;, &amp;quot;WenQuanYi Micro Hei Mono&amp;quot;, &amp;quot;WenQuanYi Zen Hei&amp;quot;, &amp;quot;WenQuanYi Zen Hei Mono&amp;quot;, &amp;quot;Noto Sans CJK SC&amp;quot;, &amp;quot;Source Han Sans CN&amp;quot;, SimSun, sans-serif; text-wrap-mode: wrap; background-color: rgb(255, 255, 255);&quot; class=&quot; list-paddingleft-2&quot;&gt;&lt;li&gt;&lt;p&gt;检查 “Service/Docks” 这个根服务结点是否存在，如果不存在，说明没有任何子服务注册，就不需要继续了；&lt;/p&gt;&lt;/li&gt;&lt;li&gt;&lt;p&gt;创建一个 IQParams 接口的实例 AParams，添加一个名为 Parent 的参数，考虑到64位编译的支持，这里类型定义为了ptUInt64（64位无符号整数）。这个 Parent 参数，用来传递给子窗体，告诉它要嵌入的目标控件地址（TWinControl 的子类）。&lt;/p&gt;&lt;/li&gt;&lt;li&gt;&lt;p&gt;循环遍历每一个注册的子服务，调用其Execute方法，并将 AParams 做为参数传递进去，以执行服务。&lt;/p&gt;&lt;/li&gt;&lt;/ul&gt;&lt;p style=&quot;line-height: 1.7; margin-top: 0px; margin-bottom: 1em; color: rgb(51, 51, 51); font-family: &amp;quot;Lucida Grande&amp;quot;, &amp;quot;Helvetica Neue&amp;quot;, Helvetica, Arial, Verdana, &amp;quot;PingFang SC&amp;quot;, &amp;quot;Hiragino Sans GB&amp;quot;, STHeiti, &amp;quot;Microsoft YaHei&amp;quot;, &amp;quot;WenQuanYi Micro Hei&amp;quot;, &amp;quot;WenQuanYi Micro Hei Mono&amp;quot;, &amp;quot;WenQuanYi Zen Hei&amp;quot;, &amp;quot;WenQuanYi Zen Hei Mono&amp;quot;, &amp;quot;Noto Sans CJK SC&amp;quot;, &amp;quot;Source Han Sans CN&amp;quot;, SimSun, sans-serif; text-wrap-mode: wrap; background-color: rgb(255, 255, 255);&quot;&gt;好了，主窗体单元所要做的一切都已OK了，我们接下来实现子窗体的服务了。因为所有的窗体嵌入这块，实际上可以共用同样的代码，所以我们将其提炼一下，将其写到了 dockservice 单元。我们来看它的源码：&lt;/p&gt;&lt;pre class=&quot;lang:delphi decode:true&quot; style=&quot;font-family: Monaco, Menlo, Consolas, Inconsolata, &amp;quot;Deja Vu Sans Mono&amp;quot;, &amp;quot;Droid Sans Mono&amp;quot;, &amp;quot;Lucida Console&amp;quot;, &amp;quot;Courier New&amp;quot;, Courier, monospace; text-wrap-mode: wrap; overflow-wrap: break-word; padding: 2em; background-color: rgb(247, 247, 247); color: rgb(51, 51, 51);&quot;&gt;unit&amp;nbsp;dockservice;

interface

uses&amp;nbsp;classes,&amp;nbsp;qstring,&amp;nbsp;qplugins,&amp;nbsp;controls;

type
&amp;nbsp;&amp;nbsp;TDockService&amp;nbsp;=&amp;nbsp;class(TQService)
&amp;nbsp;&amp;nbsp;private
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;FControlClass:&amp;nbsp;TControlClass;
&amp;nbsp;&amp;nbsp;public
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;function&amp;nbsp;Execute(AParams:&amp;nbsp;IQParams;&amp;nbsp;AResult:&amp;nbsp;IQParams):&amp;nbsp;Boolean;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;override;&amp;nbsp;stdcall;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;property&amp;nbsp;ControlClass:&amp;nbsp;TControlClass&amp;nbsp;read&amp;nbsp;FControlClass&amp;nbsp;write&amp;nbsp;FControlClass;
&amp;nbsp;&amp;nbsp;end;

const
&amp;nbsp;&amp;nbsp;IDockServices:&amp;nbsp;TGuid&amp;nbsp;=&amp;nbsp;&amp;#39;{9DDD6DD9-3053-4EE2-90D5-759267DBB10C}&amp;#39;;
procedure&amp;nbsp;RegisterDock(AClass:&amp;nbsp;TControlClass);

implementation

{&amp;nbsp;TDockService&amp;nbsp;}

function&amp;nbsp;TDockService.Execute(AParams,&amp;nbsp;AResult:&amp;nbsp;IQParams):&amp;nbsp;Boolean;
var
&amp;nbsp;&amp;nbsp;AParent:&amp;nbsp;TWinControl;
&amp;nbsp;&amp;nbsp;AControl:&amp;nbsp;TControl;
begin
&amp;nbsp;&amp;nbsp;AParent&amp;nbsp;:=&amp;nbsp;Pointer(AParams[0].AsInt64);
&amp;nbsp;&amp;nbsp;AControl&amp;nbsp;:=&amp;nbsp;ControlClass.Create(AParent);
&amp;nbsp;&amp;nbsp;AControl.HostDockSite&amp;nbsp;:=&amp;nbsp;AParent;
&amp;nbsp;&amp;nbsp;AControl.Visible&amp;nbsp;:=&amp;nbsp;True;
&amp;nbsp;&amp;nbsp;AControl.Align&amp;nbsp;:=&amp;nbsp;alClient;
&amp;nbsp;&amp;nbsp;Result&amp;nbsp;:=&amp;nbsp;True;
end;

procedure&amp;nbsp;RegisterDock(AClass:&amp;nbsp;TControlClass);
var
&amp;nbsp;&amp;nbsp;AParent:&amp;nbsp;IQServices;
&amp;nbsp;&amp;nbsp;AService:&amp;nbsp;TDockService;
begin
&amp;nbsp;&amp;nbsp;AParent&amp;nbsp;:=&amp;nbsp;PluginsManager.ById(IDockServices)&amp;nbsp;as&amp;nbsp;IQServices;
&amp;nbsp;&amp;nbsp;AService&amp;nbsp;:=&amp;nbsp;TDockService.Create(NewId,&amp;nbsp;AClass.ClassName);
&amp;nbsp;&amp;nbsp;AService.ControlClass&amp;nbsp;:=&amp;nbsp;AClass;
&amp;nbsp;&amp;nbsp;AParent.Add(AService);
end;

procedure&amp;nbsp;RegisterClass;
begin
&amp;nbsp;&amp;nbsp;PluginsManager.Services.Add(TQServices.Create(IDockServices,&amp;nbsp;&amp;#39;Docks&amp;#39;));
end;

initialization

RegisterClass;

end.&lt;/pre&gt;&lt;p style=&quot;line-height: 1.7; margin-top: 0px; margin-bottom: 1em; color: rgb(51, 51, 51); font-family: &amp;quot;Lucida Grande&amp;quot;, &amp;quot;Helvetica Neue&amp;quot;, Helvetica, Arial, Verdana, &amp;quot;PingFang SC&amp;quot;, &amp;quot;Hiragino Sans GB&amp;quot;, STHeiti, &amp;quot;Microsoft YaHei&amp;quot;, &amp;quot;WenQuanYi Micro Hei&amp;quot;, &amp;quot;WenQuanYi Micro Hei Mono&amp;quot;, &amp;quot;WenQuanYi Zen Hei&amp;quot;, &amp;quot;WenQuanYi Zen Hei Mono&amp;quot;, &amp;quot;Noto Sans CJK SC&amp;quot;, &amp;quot;Source Han Sans CN&amp;quot;, SimSun, sans-serif; text-wrap-mode: wrap; background-color: rgb(255, 255, 255);&quot;&gt;很短的一段代码，TDockService 继承自 TQService，并重载了 Execute 方法，以便提供服务的实现。另外，定义了一个 ControlClass 属性，来指定要嵌入的控件类型。剩下还有两个方法：&lt;/p&gt;&lt;ul style=&quot;box-sizing: border-box; color: rgb(51, 51, 51); font-family: &amp;quot;Lucida Grande&amp;quot;, &amp;quot;Helvetica Neue&amp;quot;, Helvetica, Arial, Verdana, &amp;quot;PingFang SC&amp;quot;, &amp;quot;Hiragino Sans GB&amp;quot;, STHeiti, &amp;quot;Microsoft YaHei&amp;quot;, &amp;quot;WenQuanYi Micro Hei&amp;quot;, &amp;quot;WenQuanYi Micro Hei Mono&amp;quot;, &amp;quot;WenQuanYi Zen Hei&amp;quot;, &amp;quot;WenQuanYi Zen Hei Mono&amp;quot;, &amp;quot;Noto Sans CJK SC&amp;quot;, &amp;quot;Source Han Sans CN&amp;quot;, SimSun, sans-serif; text-wrap-mode: wrap; background-color: rgb(255, 255, 255);&quot; class=&quot; list-paddingleft-2&quot;&gt;&lt;li&gt;&lt;p&gt;RegisterDock 是一个简单的二次封装，让用户直接调用并传递要嵌入的控件类型就OK，不去再关心注册服务的问题。&lt;/p&gt;&lt;/li&gt;&lt;li&gt;&lt;p&gt;RegisterClass 用来在 “Serivces” &amp;nbsp;下，添加一个名为 “Docks” 的子结点。好吧，回过头看前面，知道 “Services/Docks” 来自于那里了吧:)&lt;/p&gt;&lt;/li&gt;&lt;/ul&gt;&lt;p style=&quot;line-height: 1.7; margin-top: 0px; margin-bottom: 1em; color: rgb(51, 51, 51); font-family: &amp;quot;Lucida Grande&amp;quot;, &amp;quot;Helvetica Neue&amp;quot;, Helvetica, Arial, Verdana, &amp;quot;PingFang SC&amp;quot;, &amp;quot;Hiragino Sans GB&amp;quot;, STHeiti, &amp;quot;Microsoft YaHei&amp;quot;, &amp;quot;WenQuanYi Micro Hei&amp;quot;, &amp;quot;WenQuanYi Micro Hei Mono&amp;quot;, &amp;quot;WenQuanYi Zen Hei&amp;quot;, &amp;quot;WenQuanYi Zen Hei Mono&amp;quot;, &amp;quot;Noto Sans CJK SC&amp;quot;, &amp;quot;Source Han Sans CN&amp;quot;, SimSun, sans-serif; text-wrap-mode: wrap; background-color: rgb(255, 255, 255);&quot;&gt;最后，我们在 initialization 里注册调用 RegisterClass 来初始化注册 “Service/Docks” &amp;nbsp;这个服务列表。&lt;/p&gt;&lt;p style=&quot;line-height: 1.7; margin-top: 0px; margin-bottom: 1em; color: rgb(51, 51, 51); font-family: &amp;quot;Lucida Grande&amp;quot;, &amp;quot;Helvetica Neue&amp;quot;, Helvetica, Arial, Verdana, &amp;quot;PingFang SC&amp;quot;, &amp;quot;Hiragino Sans GB&amp;quot;, STHeiti, &amp;quot;Microsoft YaHei&amp;quot;, &amp;quot;WenQuanYi Micro Hei&amp;quot;, &amp;quot;WenQuanYi Micro Hei Mono&amp;quot;, &amp;quot;WenQuanYi Zen Hei&amp;quot;, &amp;quot;WenQuanYi Zen Hei Mono&amp;quot;, &amp;quot;Noto Sans CJK SC&amp;quot;, &amp;quot;Source Han Sans CN&amp;quot;, SimSun, sans-serif; text-wrap-mode: wrap; background-color: rgb(255, 255, 255);&quot;&gt;好了，现在我们随便设计两个窗体单元，在 Unit2 和 Unit3 中，窗体上你随心放置一些组件用于演示的目的。然后我们引入 qdockservices 单元，然后添加 initialization 小节，加入 RegisterDock 的调用来注册窗体类别，示例如下：&lt;/p&gt;&lt;pre class=&quot;lang:delphi decode:true&quot; style=&quot;font-family: Monaco, Menlo, Consolas, Inconsolata, &amp;quot;Deja Vu Sans Mono&amp;quot;, &amp;quot;Droid Sans Mono&amp;quot;, &amp;quot;Lucida Console&amp;quot;, &amp;quot;Courier New&amp;quot;, Courier, monospace; text-wrap-mode: wrap; overflow-wrap: break-word; padding: 2em; background-color: rgb(247, 247, 247); color: rgb(51, 51, 51);&quot;&gt;uses&amp;nbsp;dockservice;
{$R&amp;nbsp;*.dfm}

initialization

RegisterDock(TForm2);

end.&lt;/pre&gt;&lt;p style=&quot;line-height: 1.7; margin-top: 0px; margin-bottom: 1em; color: rgb(51, 51, 51); font-family: &amp;quot;Lucida Grande&amp;quot;, &amp;quot;Helvetica Neue&amp;quot;, Helvetica, Arial, Verdana, &amp;quot;PingFang SC&amp;quot;, &amp;quot;Hiragino Sans GB&amp;quot;, STHeiti, &amp;quot;Microsoft YaHei&amp;quot;, &amp;quot;WenQuanYi Micro Hei&amp;quot;, &amp;quot;WenQuanYi Micro Hei Mono&amp;quot;, &amp;quot;WenQuanYi Zen Hei&amp;quot;, &amp;quot;WenQuanYi Zen Hei Mono&amp;quot;, &amp;quot;Noto Sans CJK SC&amp;quot;, &amp;quot;Source Han Sans CN&amp;quot;, SimSun, sans-serif; text-wrap-mode: wrap; background-color: rgb(255, 255, 255);&quot;&gt;好吧，我们的第一个基于 QPlugins 松散耦合，面向服务的程序就此诞生了。现在我们 F9 运行它，可以看到两个窗体被正确的嵌入到相应的位置了：&lt;/p&gt;&lt;p style=&quot;line-height: 1.7; margin-top: 0px; margin-bottom: 1em; color: rgb(51, 51, 51); font-family: &amp;quot;Lucida Grande&amp;quot;, &amp;quot;Helvetica Neue&amp;quot;, Helvetica, Arial, Verdana, &amp;quot;PingFang SC&amp;quot;, &amp;quot;Hiragino Sans GB&amp;quot;, STHeiti, &amp;quot;Microsoft YaHei&amp;quot;, &amp;quot;WenQuanYi Micro Hei&amp;quot;, &amp;quot;WenQuanYi Micro Hei Mono&amp;quot;, &amp;quot;WenQuanYi Zen Hei&amp;quot;, &amp;quot;WenQuanYi Zen Hei Mono&amp;quot;, &amp;quot;Noto Sans CJK SC&amp;quot;, &amp;quot;Source Han Sans CN&amp;quot;, SimSun, sans-serif; text-wrap-mode: wrap; background-color: rgb(255, 255, 255);&quot;&gt;&lt;a href=&quot;https://blog.qdac.cc/wp-content/uploads/2016/01/qplugins_inprocess_docks-1.gif&quot; rel=&quot;attachment wp-att-3435&quot; style=&quot;text-decoration-line: none; color: rgb(22, 160, 133); transition: color 0.2s;&quot;&gt;&lt;img fetchpriority=&quot;high&quot; decoding=&quot;async&quot; class=&quot;wp-image-3436 size-full aligncenter&quot; src=&quot;https://blog.qdac.cc/wp-content/uploads/2016/01/qplugins_inprocess_docks-1.gif&quot; alt=&quot;&quot; width=&quot;655&quot; height=&quot;388&quot; style=&quot;height: auto; max-width: 100%; border: 0px; clear: both; display: block; margin: 0px auto;&quot;/&gt;&lt;/a&gt;&lt;/p&gt;&lt;p style=&quot;line-height: 1.7; margin-top: 0px; margin-bottom: 1em; color: rgb(51, 51, 51); font-family: &amp;quot;Lucida Grande&amp;quot;, &amp;quot;Helvetica Neue&amp;quot;, Helvetica, Arial, Verdana, &amp;quot;PingFang SC&amp;quot;, &amp;quot;Hiragino Sans GB&amp;quot;, STHeiti, &amp;quot;Microsoft YaHei&amp;quot;, &amp;quot;WenQuanYi Micro Hei&amp;quot;, &amp;quot;WenQuanYi Micro Hei Mono&amp;quot;, &amp;quot;WenQuanYi Zen Hei&amp;quot;, &amp;quot;WenQuanYi Zen Hei Mono&amp;quot;, &amp;quot;Noto Sans CJK SC&amp;quot;, &amp;quot;Source Han Sans CN&amp;quot;, SimSun, sans-serif; text-wrap-mode: wrap; background-color: rgb(255, 255, 255);&quot;&gt;简单总结一下 QPlugins 程序编写的几个步骤：&lt;/p&gt;&lt;p style=&quot;line-height: 1.7; margin-top: 0px; margin-bottom: 1em; color: rgb(51, 51, 51); font-family: &amp;quot;Lucida Grande&amp;quot;, &amp;quot;Helvetica Neue&amp;quot;, Helvetica, Arial, Verdana, &amp;quot;PingFang SC&amp;quot;, &amp;quot;Hiragino Sans GB&amp;quot;, STHeiti, &amp;quot;Microsoft YaHei&amp;quot;, &amp;quot;WenQuanYi Micro Hei&amp;quot;, &amp;quot;WenQuanYi Micro Hei Mono&amp;quot;, &amp;quot;WenQuanYi Zen Hei&amp;quot;, &amp;quot;WenQuanYi Zen Hei Mono&amp;quot;, &amp;quot;Noto Sans CJK SC&amp;quot;, &amp;quot;Source Han Sans CN&amp;quot;, SimSun, sans-serif; text-wrap-mode: wrap; background-color: rgb(255, 255, 255);&quot;&gt;&lt;strong&gt;【服务的消费者】-本示例中是主窗体单元&lt;/strong&gt;&lt;/p&gt;&lt;p style=&quot;line-height: 1.7; margin-top: 0px; margin-bottom: 1em; color: rgb(51, 51, 51); font-family: &amp;quot;Lucida Grande&amp;quot;, &amp;quot;Helvetica Neue&amp;quot;, Helvetica, Arial, Verdana, &amp;quot;PingFang SC&amp;quot;, &amp;quot;Hiragino Sans GB&amp;quot;, STHeiti, &amp;quot;Microsoft YaHei&amp;quot;, &amp;quot;WenQuanYi Micro Hei&amp;quot;, &amp;quot;WenQuanYi Micro Hei Mono&amp;quot;, &amp;quot;WenQuanYi Zen Hei&amp;quot;, &amp;quot;WenQuanYi Zen Hei Mono&amp;quot;, &amp;quot;Noto Sans CJK SC&amp;quot;, &amp;quot;Source Han Sans CN&amp;quot;, SimSun, sans-serif; text-wrap-mode: wrap; background-color: rgb(255, 255, 255);&quot;&gt;1、通过路径或ID来查找服务（本示例通过路径）；&lt;/p&gt;&lt;p style=&quot;line-height: 1.7; margin-top: 0px; margin-bottom: 1em; color: rgb(51, 51, 51); font-family: &amp;quot;Lucida Grande&amp;quot;, &amp;quot;Helvetica Neue&amp;quot;, Helvetica, Arial, Verdana, &amp;quot;PingFang SC&amp;quot;, &amp;quot;Hiragino Sans GB&amp;quot;, STHeiti, &amp;quot;Microsoft YaHei&amp;quot;, &amp;quot;WenQuanYi Micro Hei&amp;quot;, &amp;quot;WenQuanYi Micro Hei Mono&amp;quot;, &amp;quot;WenQuanYi Zen Hei&amp;quot;, &amp;quot;WenQuanYi Zen Hei Mono&amp;quot;, &amp;quot;Noto Sans CJK SC&amp;quot;, &amp;quot;Source Han Sans CN&amp;quot;, SimSun, sans-serif; text-wrap-mode: wrap; background-color: rgb(255, 255, 255);&quot;&gt;2、通过接口或者服务的 Execute 方法来调用服务（本示例调用 Execute 方法）；&lt;/p&gt;&lt;p style=&quot;line-height: 1.7; margin-top: 0px; margin-bottom: 1em; color: rgb(51, 51, 51); font-family: &amp;quot;Lucida Grande&amp;quot;, &amp;quot;Helvetica Neue&amp;quot;, Helvetica, Arial, Verdana, &amp;quot;PingFang SC&amp;quot;, &amp;quot;Hiragino Sans GB&amp;quot;, STHeiti, &amp;quot;Microsoft YaHei&amp;quot;, &amp;quot;WenQuanYi Micro Hei&amp;quot;, &amp;quot;WenQuanYi Micro Hei Mono&amp;quot;, &amp;quot;WenQuanYi Zen Hei&amp;quot;, &amp;quot;WenQuanYi Zen Hei Mono&amp;quot;, &amp;quot;Noto Sans CJK SC&amp;quot;, &amp;quot;Source Han Sans CN&amp;quot;, SimSun, sans-serif; text-wrap-mode: wrap; background-color: rgb(255, 255, 255);&quot;&gt;&lt;strong&gt;【服务的提供者】-本示例中为各个子窗体实现单元&lt;/strong&gt;&lt;/p&gt;&lt;p style=&quot;line-height: 1.7; margin-top: 0px; margin-bottom: 1em; color: rgb(51, 51, 51); font-family: &amp;quot;Lucida Grande&amp;quot;, &amp;quot;Helvetica Neue&amp;quot;, Helvetica, Arial, Verdana, &amp;quot;PingFang SC&amp;quot;, &amp;quot;Hiragino Sans GB&amp;quot;, STHeiti, &amp;quot;Microsoft YaHei&amp;quot;, &amp;quot;WenQuanYi Micro Hei&amp;quot;, &amp;quot;WenQuanYi Micro Hei Mono&amp;quot;, &amp;quot;WenQuanYi Zen Hei&amp;quot;, &amp;quot;WenQuanYi Zen Hei Mono&amp;quot;, &amp;quot;Noto Sans CJK SC&amp;quot;, &amp;quot;Source Han Sans CN&amp;quot;, SimSun, sans-serif; text-wrap-mode: wrap; background-color: rgb(255, 255, 255);&quot;&gt;1、实现 IQService 接口和自己特定的接口（本示例没有特定的接口，直接继承 TQService 并实现了Execute 方法）；&lt;/p&gt;&lt;p style=&quot;line-height: 1.7; margin-top: 0px; margin-bottom: 1em; color: rgb(51, 51, 51); font-family: &amp;quot;Lucida Grande&amp;quot;, &amp;quot;Helvetica Neue&amp;quot;, Helvetica, Arial, Verdana, &amp;quot;PingFang SC&amp;quot;, &amp;quot;Hiragino Sans GB&amp;quot;, STHeiti, &amp;quot;Microsoft YaHei&amp;quot;, &amp;quot;WenQuanYi Micro Hei&amp;quot;, &amp;quot;WenQuanYi Micro Hei Mono&amp;quot;, &amp;quot;WenQuanYi Zen Hei&amp;quot;, &amp;quot;WenQuanYi Zen Hei Mono&amp;quot;, &amp;quot;Noto Sans CJK SC&amp;quot;, &amp;quot;Source Han Sans CN&amp;quot;, SimSun, sans-serif; text-wrap-mode: wrap; background-color: rgb(255, 255, 255);&quot;&gt;2、在单元的 initialization 小节中，注册自己到编写的服务路径下（本示例中的 “Services/Docks”）；&lt;/p&gt;&lt;p&gt;&lt;br/&gt;&lt;/p&gt;</description><pubDate>Thu, 21 Nov 2024 17:41:12 +0800</pubDate></item><item><title>一个共享的计时器类封装</title><link>http://51scm.net/?id=7</link><description>&lt;p style=&quot;line-height: 1.7; margin-top: -0.3em; margin-bottom: 1em; color: rgb(51, 51, 51); font-family: &amp;quot;Lucida Grande&amp;quot;, &amp;quot;Helvetica Neue&amp;quot;, Helvetica, Arial, Verdana, &amp;quot;PingFang SC&amp;quot;, &amp;quot;Hiragino Sans GB&amp;quot;, STHeiti, &amp;quot;Microsoft YaHei&amp;quot;, &amp;quot;WenQuanYi Micro Hei&amp;quot;, &amp;quot;WenQuanYi Micro Hei Mono&amp;quot;, &amp;quot;WenQuanYi Zen Hei&amp;quot;, &amp;quot;WenQuanYi Zen Hei Mono&amp;quot;, &amp;quot;Noto Sans CJK SC&amp;quot;, &amp;quot;Source Han Sans CN&amp;quot;, SimSun, sans-serif; text-wrap: wrap; background-color: rgb(255, 255, 255);&quot;&gt;&lt;strong&gt;QDAC 4.0 中已经包含了此单元，名称改为qdac.timer.share，使用 TQShareTimer 来做相关处理。&lt;/strong&gt;&lt;/p&gt;&lt;p style=&quot;line-height: 1.7; margin-top: 0px; margin-bottom: 1em; color: rgb(51, 51, 51); font-family: &amp;quot;Lucida Grande&amp;quot;, &amp;quot;Helvetica Neue&amp;quot;, Helvetica, Arial, Verdana, &amp;quot;PingFang SC&amp;quot;, &amp;quot;Hiragino Sans GB&amp;quot;, STHeiti, &amp;quot;Microsoft YaHei&amp;quot;, &amp;quot;WenQuanYi Micro Hei&amp;quot;, &amp;quot;WenQuanYi Micro Hei Mono&amp;quot;, &amp;quot;WenQuanYi Zen Hei&amp;quot;, &amp;quot;WenQuanYi Zen Hei Mono&amp;quot;, &amp;quot;Noto Sans CJK SC&amp;quot;, &amp;quot;Source Han Sans CN&amp;quot;, SimSun, sans-serif; text-wrap: wrap; background-color: rgb(255, 255, 255);&quot;&gt;这个是一个精度为秒的共享定时器实现，可以秒为单位创建多个共享的定时器，这些定时器的回调的维护和回调都要求在主线程中执行。&lt;/p&gt;&lt;p style=&quot;line-height: 1.7; margin-top: 0px; margin-bottom: 1em; color: rgb(51, 51, 51); font-family: &amp;quot;Lucida Grande&amp;quot;, &amp;quot;Helvetica Neue&amp;quot;, Helvetica, Arial, Verdana, &amp;quot;PingFang SC&amp;quot;, &amp;quot;Hiragino Sans GB&amp;quot;, STHeiti, &amp;quot;Microsoft YaHei&amp;quot;, &amp;quot;WenQuanYi Micro Hei&amp;quot;, &amp;quot;WenQuanYi Micro Hei Mono&amp;quot;, &amp;quot;WenQuanYi Zen Hei&amp;quot;, &amp;quot;WenQuanYi Zen Hei Mono&amp;quot;, &amp;quot;Noto Sans CJK SC&amp;quot;, &amp;quot;Source Han Sans CN&amp;quot;, SimSun, sans-serif; text-wrap: wrap; background-color: rgb(255, 255, 255);&quot;&gt;这个代码真正想给大家说的是 GetCallbackOwner 函数中，关于匿名函数关联的 Self 的地址获取方式。至于其它实现，实际上大家应该很容易就能看到。&lt;/p&gt;&lt;ul style=&quot;box-sizing: border-box; color: rgb(51, 51, 51); font-family: &amp;quot;Lucida Grande&amp;quot;, &amp;quot;Helvetica Neue&amp;quot;, Helvetica, Arial, Verdana, &amp;quot;PingFang SC&amp;quot;, &amp;quot;Hiragino Sans GB&amp;quot;, STHeiti, &amp;quot;Microsoft YaHei&amp;quot;, &amp;quot;WenQuanYi Micro Hei&amp;quot;, &amp;quot;WenQuanYi Micro Hei Mono&amp;quot;, &amp;quot;WenQuanYi Zen Hei&amp;quot;, &amp;quot;WenQuanYi Zen Hei Mono&amp;quot;, &amp;quot;Noto Sans CJK SC&amp;quot;, &amp;quot;Source Han Sans CN&amp;quot;, SimSun, sans-serif; text-wrap: wrap; background-color: rgb(255, 255, 255);&quot; class=&quot; list-paddingleft-2&quot;&gt;&lt;li&gt;&lt;p&gt;___Parent 成员指向自己的一层匿名函数的实例地址&lt;/p&gt;&lt;/li&gt;&lt;li&gt;&lt;p&gt;Self 成员指向关联的 Self 实例地址&lt;/p&gt;&lt;/li&gt;&lt;li&gt;&lt;p&gt;通过递归找到 Self&lt;/p&gt;&lt;/li&gt;&lt;/ul&gt;&lt;pre class=&quot;prism-highlight prism-language-pascal&quot;&gt;unit&amp;nbsp;Timer.share;

interface

uses&amp;nbsp;System.Classes,&amp;nbsp;System.Sysutils,&amp;nbsp;System.Generics.Collections,&amp;nbsp;System.Generics.Defaults,&amp;nbsp;System.Rtti,&amp;nbsp;Vcl.ExtCtrls,
&amp;nbsp;&amp;nbsp;Winapi.Windows;

type

&amp;nbsp;&amp;nbsp;PShareTimerItem&amp;nbsp;=&amp;nbsp;^TShareTimerItem;

&amp;nbsp;&amp;nbsp;//&amp;nbsp;共享定时器项目定义
&amp;nbsp;&amp;nbsp;TShareTimerItem&amp;nbsp;=&amp;nbsp;record
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;//&amp;nbsp;回调函数
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;Callback:&amp;nbsp;TMethod;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;//&amp;nbsp;末次触发时间
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;LastTick:&amp;nbsp;UInt64;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;//&amp;nbsp;定时器间隔，单位为毫秒（注意添加时用的单位是秒，内部换算成毫秒，以减少1次计算
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;Interval:&amp;nbsp;Cardinal;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;//&amp;nbsp;触发次数
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;Times:&amp;nbsp;Cardinal;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;//&amp;nbsp;引用计数
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;RefCount:&amp;nbsp;Integer;
&amp;nbsp;&amp;nbsp;end;

&amp;nbsp;&amp;nbsp;TTimerProc&amp;nbsp;=&amp;nbsp;procedure(const&amp;nbsp;AItem:&amp;nbsp;TShareTimerItem)&amp;nbsp;of&amp;nbsp;object;
&amp;nbsp;&amp;nbsp;TTimerProcA&amp;nbsp;=&amp;nbsp;reference&amp;nbsp;to&amp;nbsp;procedure(const&amp;nbsp;AItem:&amp;nbsp;TShareTimerItem);
&amp;nbsp;&amp;nbsp;TTimerProcG&amp;nbsp;=&amp;nbsp;procedure(const&amp;nbsp;AItem:&amp;nbsp;TShareTimerItem);

&amp;nbsp;&amp;nbsp;TShareTimer&amp;nbsp;=&amp;nbsp;class&amp;nbsp;sealed
&amp;nbsp;&amp;nbsp;private
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;class&amp;nbsp;var&amp;nbsp;FCurrent:&amp;nbsp;TShareTimer;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;class&amp;nbsp;function&amp;nbsp;GetCurrent:&amp;nbsp;TShareTimer;&amp;nbsp;static;
&amp;nbsp;&amp;nbsp;protected
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;FCallbacks:&amp;nbsp;TList&amp;lt;PShareTimerItem&amp;gt;;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;FTimerId:&amp;nbsp;Cardinal;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;class&amp;nbsp;procedure&amp;nbsp;DoTimer(wnd:&amp;nbsp;HWND;&amp;nbsp;msg:&amp;nbsp;UINT;&amp;nbsp;timerId:&amp;nbsp;UINT_PTR;&amp;nbsp;dwTime:&amp;nbsp;DWORD);&amp;nbsp;static;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;procedure&amp;nbsp;InternalAdd(const&amp;nbsp;AMethod:&amp;nbsp;TMethod;&amp;nbsp;AInterval:&amp;nbsp;Cardinal);
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;procedure&amp;nbsp;InternalRemove(const&amp;nbsp;AMethod:&amp;nbsp;TMethod);
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;procedure&amp;nbsp;DoListNotify(Sender:&amp;nbsp;TObject;&amp;nbsp;const&amp;nbsp;Item:&amp;nbsp;PShareTimerItem;&amp;nbsp;Action:&amp;nbsp;TCollectionNotification);
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;function&amp;nbsp;DoClear(Owner:&amp;nbsp;TObject):&amp;nbsp;Integer;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;procedure&amp;nbsp;FreeTimer(ATimer:&amp;nbsp;PShareTimerItem);
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;//&amp;nbsp;获取定时器关联的所有者对象实例(即回调函数中&amp;nbsp;Self&amp;nbsp;对应的值，如果是全局回调，则为空)
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;function&amp;nbsp;GetCallbackOwner(const&amp;nbsp;ATimer:&amp;nbsp;TShareTimerItem):&amp;nbsp;TObject;
&amp;nbsp;&amp;nbsp;public
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;constructor&amp;nbsp;Create;&amp;nbsp;overload;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;destructor&amp;nbsp;Destroy;&amp;nbsp;override;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;class&amp;nbsp;destructor&amp;nbsp;Destroy;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;///&amp;nbsp;&amp;lt;summary&amp;gt;清除所有的定时器&amp;lt;summary&amp;gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;class&amp;nbsp;procedure&amp;nbsp;Clear;&amp;nbsp;overload;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;///&amp;nbsp;&amp;lt;summary&amp;gt;清除关联到指定对象的所有定时器&amp;lt;/summary&amp;gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;///&amp;nbsp;&amp;lt;param&amp;nbsp;name=&amp;quot;Owner&amp;quot;&amp;gt;所有者对象&amp;lt;/param&amp;gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;///&amp;nbsp;&amp;lt;remark&amp;gt;对于对象的成员函数，Owner&amp;nbsp;为对象的地址，对于匿名函数，则指向对应的回调函数的&amp;nbsp;Self&amp;nbsp;成员&amp;lt;/remark&amp;gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;class&amp;nbsp;function&amp;nbsp;Clear(Owner:&amp;nbsp;TObject):&amp;nbsp;Integer;&amp;nbsp;overload;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;///&amp;nbsp;&amp;lt;summary&amp;gt;添加一个定时器回调&amp;lt;/summary&amp;gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;///&amp;nbsp;&amp;lt;param&amp;nbsp;name=&amp;quot;ACallback&amp;quot;&amp;gt;定时器回调函数&amp;lt;/param&amp;gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;///&amp;nbsp;&amp;lt;param&amp;nbsp;name=&amp;quot;AInterval&amp;quot;&amp;gt;定时器间隔，单位为秒&amp;lt;/param&amp;gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;class&amp;nbsp;procedure&amp;nbsp;Add(ACallback:&amp;nbsp;TTimerProc;&amp;nbsp;AInterval:&amp;nbsp;Cardinal&amp;nbsp;=&amp;nbsp;1);&amp;nbsp;overload;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;///&amp;nbsp;&amp;lt;summary&amp;gt;添加一个定时器回调&amp;lt;/summary&amp;gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;///&amp;nbsp;&amp;lt;param&amp;nbsp;name=&amp;quot;ACallback&amp;quot;&amp;gt;定时器回调函数&amp;lt;/param&amp;gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;///&amp;nbsp;&amp;lt;param&amp;nbsp;name=&amp;quot;AInterval&amp;quot;&amp;gt;定时器间隔，单位为秒&amp;lt;/param&amp;gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;class&amp;nbsp;procedure&amp;nbsp;Add(ACallback:&amp;nbsp;TTimerProcG;&amp;nbsp;AInterval:&amp;nbsp;Cardinal&amp;nbsp;=&amp;nbsp;1);&amp;nbsp;overload;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;///&amp;nbsp;&amp;lt;summary&amp;gt;添加一个定时器回调&amp;lt;/summary&amp;gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;///&amp;nbsp;&amp;lt;param&amp;nbsp;name=&amp;quot;ACallback&amp;quot;&amp;gt;定时器回调函数&amp;lt;/param&amp;gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;///&amp;nbsp;&amp;lt;param&amp;nbsp;name=&amp;quot;AInterval&amp;quot;&amp;gt;定时器间隔，单位为秒&amp;lt;/param&amp;gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;class&amp;nbsp;procedure&amp;nbsp;Add(ACallback:&amp;nbsp;TTimerProcA;&amp;nbsp;AInterval:&amp;nbsp;Cardinal&amp;nbsp;=&amp;nbsp;1);&amp;nbsp;overload;

&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;///&amp;nbsp;&amp;lt;summary&amp;gt;删除一个定时器回调&amp;lt;/summary&amp;gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;///&amp;nbsp;&amp;lt;param&amp;nbsp;name=&amp;quot;ACallback&amp;quot;&amp;gt;定时器回调函数&amp;lt;/param&amp;gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;class&amp;nbsp;procedure&amp;nbsp;Remove(ACallback:&amp;nbsp;TTimerProc);&amp;nbsp;overload;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;///&amp;nbsp;&amp;lt;summary&amp;gt;删除一个定时器回调&amp;lt;/summary&amp;gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;///&amp;nbsp;&amp;lt;param&amp;nbsp;name=&amp;quot;ACallback&amp;quot;&amp;gt;定时器回调函数&amp;lt;/param&amp;gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;class&amp;nbsp;procedure&amp;nbsp;Remove(ACallback:&amp;nbsp;TTimerProcG);&amp;nbsp;overload;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;///&amp;nbsp;&amp;lt;summary&amp;gt;删除一个定时器回调&amp;lt;/summary&amp;gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;///&amp;nbsp;&amp;lt;param&amp;nbsp;name=&amp;quot;ACallback&amp;quot;&amp;gt;定时器回调函数&amp;lt;/param&amp;gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;///&amp;nbsp;&amp;lt;remarks&amp;gt;注意匿名函数是一个接口，每次调用会对应不同的实例，这个需要自己注意管理。
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;///&amp;nbsp;如果要清除一个对象的所有定时器，调用&amp;nbsp;Clear(对象实例)
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;///&amp;nbsp;&amp;lt;remarks&amp;gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;class&amp;nbsp;procedure&amp;nbsp;Remove(ACallback:&amp;nbsp;TTimerProcA);&amp;nbsp;overload;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;///&amp;nbsp;全局公共实例
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;class&amp;nbsp;property&amp;nbsp;Current:&amp;nbsp;TShareTimer&amp;nbsp;read&amp;nbsp;GetCurrent;
&amp;nbsp;&amp;nbsp;end;

implementation

{&amp;nbsp;TShareTimer&amp;nbsp;}

class&amp;nbsp;procedure&amp;nbsp;TShareTimer.Add(ACallback:&amp;nbsp;TTimerProc;&amp;nbsp;AInterval:&amp;nbsp;Cardinal);
begin
&amp;nbsp;&amp;nbsp;Current.InternalAdd(TMethod(ACallback),&amp;nbsp;AInterval&amp;nbsp;*&amp;nbsp;1000);
end;

class&amp;nbsp;procedure&amp;nbsp;TShareTimer.Add(ACallback:&amp;nbsp;TTimerProcG;&amp;nbsp;AInterval:&amp;nbsp;Cardinal);
var
&amp;nbsp;&amp;nbsp;AMethod:&amp;nbsp;TMethod;
begin
&amp;nbsp;&amp;nbsp;AMethod.Code&amp;nbsp;:=&amp;nbsp;@ACallback;
&amp;nbsp;&amp;nbsp;AMethod.Data&amp;nbsp;:=&amp;nbsp;nil;
&amp;nbsp;&amp;nbsp;Current.InternalAdd(AMethod,&amp;nbsp;AInterval&amp;nbsp;*&amp;nbsp;1000);
end;

class&amp;nbsp;procedure&amp;nbsp;TShareTimer.Add(ACallback:&amp;nbsp;TTimerProcA;&amp;nbsp;AInterval:&amp;nbsp;Cardinal);
var
&amp;nbsp;&amp;nbsp;AMethod:&amp;nbsp;TMethod;
begin
&amp;nbsp;&amp;nbsp;AMethod.Code&amp;nbsp;:=&amp;nbsp;nil;
&amp;nbsp;&amp;nbsp;AMethod.Data&amp;nbsp;:=&amp;nbsp;Pointer(-1);
&amp;nbsp;&amp;nbsp;TTimerProcA(AMethod.Code)&amp;nbsp;:=&amp;nbsp;ACallback;
&amp;nbsp;&amp;nbsp;Current.InternalAdd(AMethod,&amp;nbsp;AInterval&amp;nbsp;*&amp;nbsp;1000);
end;

class&amp;nbsp;procedure&amp;nbsp;TShareTimer.Clear;
begin
&amp;nbsp;&amp;nbsp;Current.FCallbacks.Clear;
end;

class&amp;nbsp;function&amp;nbsp;TShareTimer.Clear(Owner:&amp;nbsp;TObject):&amp;nbsp;Integer;
begin
&amp;nbsp;&amp;nbsp;Result&amp;nbsp;:=&amp;nbsp;Current.DoClear(Owner);
end;

constructor&amp;nbsp;TShareTimer.Create;
begin
&amp;nbsp;&amp;nbsp;inherited&amp;nbsp;Create;
&amp;nbsp;&amp;nbsp;FCallbacks&amp;nbsp;:=&amp;nbsp;TList&amp;lt;PShareTimerItem&amp;gt;.Create(TComparer&amp;lt;PShareTimerItem&amp;gt;.Construct(
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;function(const&amp;nbsp;L,&amp;nbsp;R:&amp;nbsp;PShareTimerItem):&amp;nbsp;Integer
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;begin
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;Result&amp;nbsp;:=&amp;nbsp;IntPtr(L.Callback.Code)&amp;nbsp;-&amp;nbsp;IntPtr(R.Callback.Code);
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;if&amp;nbsp;Result&amp;nbsp;=&amp;nbsp;0&amp;nbsp;then
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;Result&amp;nbsp;:=&amp;nbsp;IntPtr(L.Callback.Data)&amp;nbsp;-&amp;nbsp;IntPtr(R.Callback.Data);
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;end));
&amp;nbsp;&amp;nbsp;FCallbacks.OnNotify&amp;nbsp;:=&amp;nbsp;DoListNotify;
end;

destructor&amp;nbsp;TShareTimer.Destroy;
begin
&amp;nbsp;&amp;nbsp;FCallbacks.Clear;
&amp;nbsp;&amp;nbsp;FreeAndNil(FCallbacks);
&amp;nbsp;&amp;nbsp;inherited;
end;

class&amp;nbsp;destructor&amp;nbsp;TShareTimer.Destroy;
begin
&amp;nbsp;&amp;nbsp;if&amp;nbsp;Assigned(FCurrent)&amp;nbsp;then
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;FreeAndNil(FCurrent);
end;

function&amp;nbsp;TShareTimer.DoClear(Owner:&amp;nbsp;TObject):&amp;nbsp;Integer;
var
&amp;nbsp;&amp;nbsp;I:&amp;nbsp;Integer;
begin
&amp;nbsp;&amp;nbsp;I&amp;nbsp;:=&amp;nbsp;0;
&amp;nbsp;&amp;nbsp;Result&amp;nbsp;:=&amp;nbsp;0;
&amp;nbsp;&amp;nbsp;while&amp;nbsp;I&amp;nbsp;&amp;lt;&amp;nbsp;FCallbacks.Count&amp;nbsp;do
&amp;nbsp;&amp;nbsp;begin
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;if&amp;nbsp;GetCallbackOwner(FCallbacks[I]^)&amp;nbsp;=&amp;nbsp;Owner&amp;nbsp;then
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;begin
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;FCallbacks.Delete(I);
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;Inc(Result);
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;continue;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;end;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;Inc(I);
&amp;nbsp;&amp;nbsp;end;
end;

procedure&amp;nbsp;TShareTimer.DoListNotify(Sender:&amp;nbsp;TObject;&amp;nbsp;const&amp;nbsp;Item:&amp;nbsp;PShareTimerItem;&amp;nbsp;Action:&amp;nbsp;TCollectionNotification);
begin
&amp;nbsp;&amp;nbsp;if&amp;nbsp;Action&amp;nbsp;in&amp;nbsp;[cnExtracted,&amp;nbsp;cnRemoved]&amp;nbsp;then
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;FreeTimer(Item);
end;

class&amp;nbsp;procedure&amp;nbsp;TShareTimer.DoTimer(wnd:&amp;nbsp;HWND;&amp;nbsp;msg:&amp;nbsp;UINT;&amp;nbsp;timerId:&amp;nbsp;UINT_PTR;&amp;nbsp;dwTime:&amp;nbsp;DWORD);
var
&amp;nbsp;&amp;nbsp;ATick:&amp;nbsp;UInt64;
&amp;nbsp;&amp;nbsp;ATimers:&amp;nbsp;TArray&amp;lt;PShareTimerItem&amp;gt;;
begin
&amp;nbsp;&amp;nbsp;ATick&amp;nbsp;:=&amp;nbsp;TThread.GetTickCount64;
&amp;nbsp;&amp;nbsp;with&amp;nbsp;TShareTimer.FCurrent&amp;nbsp;do
&amp;nbsp;&amp;nbsp;begin
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;ATimers&amp;nbsp;:=&amp;nbsp;FCallbacks.ToArray;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;for&amp;nbsp;var&amp;nbsp;I&amp;nbsp;:=&amp;nbsp;0&amp;nbsp;to&amp;nbsp;High(ATimers)&amp;nbsp;do
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;Inc(ATimers[I].RefCount);
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;try
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;for&amp;nbsp;var&amp;nbsp;I&amp;nbsp;:=&amp;nbsp;0&amp;nbsp;to&amp;nbsp;High(ATimers)&amp;nbsp;do
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;begin
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;try
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;if&amp;nbsp;ATick&amp;nbsp;-&amp;nbsp;ATimers[I].LastTick&amp;nbsp;&amp;gt;=&amp;nbsp;ATimers[I].Interval&amp;nbsp;then
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;begin
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;ATimers[I].LastTick&amp;nbsp;:=&amp;nbsp;ATick;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;Inc(ATimers[I].Times);
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;case&amp;nbsp;IntPtr(ATimers[I].Callback.Data)&amp;nbsp;of
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;0:
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;TTimerProcG(ATimers[I].Callback.Code)(ATimers[I]^);
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;-1:
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;TTimerProcA(ATimers[I].Callback.Code)(ATimers[I]^)
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;else
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;TTimerProc(ATimers[I].Callback)(ATimers[I]^);
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;end;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;end;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;except
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;on&amp;nbsp;E:&amp;nbsp;Exception&amp;nbsp;do

&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;end;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;end;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;finally
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;for&amp;nbsp;var&amp;nbsp;I&amp;nbsp;:=&amp;nbsp;0&amp;nbsp;to&amp;nbsp;High(ATimers)&amp;nbsp;do
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;FreeTimer(ATimers[I]);
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;end;
&amp;nbsp;&amp;nbsp;end;
end;

procedure&amp;nbsp;TShareTimer.FreeTimer(ATimer:&amp;nbsp;PShareTimerItem);
var
&amp;nbsp;&amp;nbsp;AProc:&amp;nbsp;TTimerProcA;
begin
&amp;nbsp;&amp;nbsp;Dec(ATimer.RefCount);
&amp;nbsp;&amp;nbsp;if&amp;nbsp;ATimer.RefCount&amp;nbsp;=&amp;nbsp;0&amp;nbsp;then
&amp;nbsp;&amp;nbsp;begin
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;if&amp;nbsp;(ATimer.Callback.Data&amp;nbsp;=&amp;nbsp;Pointer(-1))&amp;nbsp;then
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;begin
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;PPointer(@AProc)^&amp;nbsp;:=&amp;nbsp;ATimer.Callback.Code;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;AProc&amp;nbsp;:=&amp;nbsp;nil;&amp;nbsp;//&amp;nbsp;引用计数
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;end;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;Dispose(ATimer);
&amp;nbsp;&amp;nbsp;end;
end;

class&amp;nbsp;function&amp;nbsp;TShareTimer.GetCurrent:&amp;nbsp;TShareTimer;
begin
&amp;nbsp;&amp;nbsp;if&amp;nbsp;not&amp;nbsp;Assigned(FCurrent)&amp;nbsp;then
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;FCurrent&amp;nbsp;:=&amp;nbsp;TShareTimer.Create;
&amp;nbsp;&amp;nbsp;Result&amp;nbsp;:=&amp;nbsp;FCurrent;
end;

function&amp;nbsp;TShareTimer.GetCallbackOwner(const&amp;nbsp;ATimer:&amp;nbsp;TShareTimerItem):&amp;nbsp;TObject;
&amp;nbsp;&amp;nbsp;function&amp;nbsp;GetObject(AObj:&amp;nbsp;TObject):&amp;nbsp;TObject;
&amp;nbsp;&amp;nbsp;var
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;AType:&amp;nbsp;TRttiType;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;AField:&amp;nbsp;TRttiField;
&amp;nbsp;&amp;nbsp;begin
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;Result&amp;nbsp;:=&amp;nbsp;nil;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;AType&amp;nbsp;:=&amp;nbsp;TRttiContext.Create.GetType(AObj.ClassType);
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;if&amp;nbsp;Assigned(AType)&amp;nbsp;then
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;begin
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;AField&amp;nbsp;:=&amp;nbsp;AType.GetField(&amp;#39;___Parent&amp;#39;);
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;if&amp;nbsp;Assigned(AField)&amp;nbsp;then
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;Result&amp;nbsp;:=&amp;nbsp;GetObject(AField.GetValue(AObj).AsObject)
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;else
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;begin
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;AField&amp;nbsp;:=&amp;nbsp;AType.GetField(&amp;#39;Self&amp;#39;);
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;if&amp;nbsp;Assigned(AField)&amp;nbsp;then
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;Result&amp;nbsp;:=&amp;nbsp;AField.GetValue(AObj).AsObject;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;end;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;end;
&amp;nbsp;&amp;nbsp;end;

var
&amp;nbsp;&amp;nbsp;I:&amp;nbsp;Integer;
begin
&amp;nbsp;&amp;nbsp;I&amp;nbsp;:=&amp;nbsp;0;
&amp;nbsp;&amp;nbsp;if&amp;nbsp;FCallbacks[I].Callback.Data&amp;nbsp;&amp;lt;&amp;gt;&amp;nbsp;nil&amp;nbsp;then
&amp;nbsp;&amp;nbsp;begin
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;if&amp;nbsp;FCallbacks[I].Callback.Data&amp;nbsp;=&amp;nbsp;Pointer(-1)&amp;nbsp;then
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;Result&amp;nbsp;:=&amp;nbsp;GetObject(IInterface(FCallbacks[I].Callback.Code)&amp;nbsp;as&amp;nbsp;TObject)
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;else
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;Result&amp;nbsp;:=&amp;nbsp;FCallbacks[I].Callback.Data;
&amp;nbsp;&amp;nbsp;end
&amp;nbsp;&amp;nbsp;else
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;Result&amp;nbsp;:=&amp;nbsp;nil;
end;

procedure&amp;nbsp;TShareTimer.InternalAdd(const&amp;nbsp;AMethod:&amp;nbsp;TMethod;&amp;nbsp;AInterval:&amp;nbsp;Cardinal);
var
&amp;nbsp;&amp;nbsp;AItem:&amp;nbsp;PShareTimerItem;
&amp;nbsp;&amp;nbsp;AIndex:&amp;nbsp;Integer;
begin
&amp;nbsp;&amp;nbsp;New(AItem);
&amp;nbsp;&amp;nbsp;AItem.Callback&amp;nbsp;:=&amp;nbsp;AMethod;
&amp;nbsp;&amp;nbsp;AItem.LastTick&amp;nbsp;:=&amp;nbsp;TThread.GetTickCount64;
&amp;nbsp;&amp;nbsp;AItem.Interval&amp;nbsp;:=&amp;nbsp;AInterval;
&amp;nbsp;&amp;nbsp;AItem.RefCount&amp;nbsp;:=&amp;nbsp;1;
&amp;nbsp;&amp;nbsp;AItem.Times&amp;nbsp;:=&amp;nbsp;0;
&amp;nbsp;&amp;nbsp;if&amp;nbsp;not&amp;nbsp;FCallbacks.BinarySearch(AItem,&amp;nbsp;AIndex)&amp;nbsp;then
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;FCallbacks.Insert(AIndex,&amp;nbsp;AItem);
&amp;nbsp;&amp;nbsp;if&amp;nbsp;FTimerId&amp;nbsp;=&amp;nbsp;0&amp;nbsp;then
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;FTimerId&amp;nbsp;:=&amp;nbsp;SetTimer(0,&amp;nbsp;0,&amp;nbsp;1000,&amp;nbsp;TFNTimerProc(@DoTimer));
end;

procedure&amp;nbsp;TShareTimer.InternalRemove(const&amp;nbsp;AMethod:&amp;nbsp;TMethod);
var
&amp;nbsp;&amp;nbsp;AIndex:&amp;nbsp;Integer;
&amp;nbsp;&amp;nbsp;ATemp:&amp;nbsp;TShareTimerItem;
begin
&amp;nbsp;&amp;nbsp;ATemp.Callback&amp;nbsp;:=&amp;nbsp;AMethod;
&amp;nbsp;&amp;nbsp;if&amp;nbsp;FCallbacks.BinarySearch(@ATemp,&amp;nbsp;AIndex)&amp;nbsp;then
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;FCallbacks.Delete(AIndex);
&amp;nbsp;&amp;nbsp;if&amp;nbsp;FCallbacks.Count&amp;nbsp;=&amp;nbsp;0&amp;nbsp;then
&amp;nbsp;&amp;nbsp;begin
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;KillTimer(0,&amp;nbsp;FTimerId);
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;FTimerId&amp;nbsp;:=&amp;nbsp;0;
&amp;nbsp;&amp;nbsp;end;
end;

class&amp;nbsp;procedure&amp;nbsp;TShareTimer.Remove(ACallback:&amp;nbsp;TTimerProc);
begin
&amp;nbsp;&amp;nbsp;if&amp;nbsp;Assigned(FCurrent)&amp;nbsp;then
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;FCurrent.InternalRemove(TMethod(ACallback));
end;

class&amp;nbsp;procedure&amp;nbsp;TShareTimer.Remove(ACallback:&amp;nbsp;TTimerProcG);
var
&amp;nbsp;&amp;nbsp;AMethod:&amp;nbsp;TMethod;
begin
&amp;nbsp;&amp;nbsp;if&amp;nbsp;Assigned(FCurrent)&amp;nbsp;then
&amp;nbsp;&amp;nbsp;begin
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;AMethod.Code&amp;nbsp;:=&amp;nbsp;@ACallback;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;AMethod.Data&amp;nbsp;:=&amp;nbsp;nil;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;FCurrent.InternalRemove(AMethod);
&amp;nbsp;&amp;nbsp;end;
end;

class&amp;nbsp;procedure&amp;nbsp;TShareTimer.Remove(ACallback:&amp;nbsp;TTimerProcA);
var
&amp;nbsp;&amp;nbsp;AMethod:&amp;nbsp;TMethod;
begin
&amp;nbsp;&amp;nbsp;if&amp;nbsp;Assigned(FCurrent)&amp;nbsp;then
&amp;nbsp;&amp;nbsp;begin
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;AMethod.Code&amp;nbsp;:=&amp;nbsp;nil;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;AMethod.Data&amp;nbsp;:=&amp;nbsp;Pointer(-1);
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;FCurrent.InternalRemove(AMethod);
&amp;nbsp;&amp;nbsp;end;
end;

end.&lt;/pre&gt;&lt;p&gt;&lt;br/&gt;&lt;/p&gt;</description><pubDate>Tue, 20 Aug 2024 17:24:42 +0800</pubDate></item><item><title>运行时动态修改 FMX 样式</title><link>http://51scm.net/?id=6</link><description>&lt;p style=&quot;line-height: 1.7; margin-top: -0.3em; margin-bottom: 1em; color: rgb(51, 51, 51); font-family: &amp;quot;Lucida Grande&amp;quot;, &amp;quot;Helvetica Neue&amp;quot;, Helvetica, Arial, Verdana, &amp;quot;PingFang SC&amp;quot;, &amp;quot;Hiragino Sans GB&amp;quot;, STHeiti, &amp;quot;Microsoft YaHei&amp;quot;, &amp;quot;WenQuanYi Micro Hei&amp;quot;, &amp;quot;WenQuanYi Micro Hei Mono&amp;quot;, &amp;quot;WenQuanYi Zen Hei&amp;quot;, &amp;quot;WenQuanYi Zen Hei Mono&amp;quot;, &amp;quot;Noto Sans CJK SC&amp;quot;, &amp;quot;Source Han Sans CN&amp;quot;, SimSun, sans-serif; text-wrap: wrap; background-color: rgb(255, 255, 255);&quot;&gt;简单说几个点：&lt;/p&gt;&lt;p style=&quot;line-height: 1.7; margin-top: 0px; margin-bottom: 1em; color: rgb(51, 51, 51); font-family: &amp;quot;Lucida Grande&amp;quot;, &amp;quot;Helvetica Neue&amp;quot;, Helvetica, Arial, Verdana, &amp;quot;PingFang SC&amp;quot;, &amp;quot;Hiragino Sans GB&amp;quot;, STHeiti, &amp;quot;Microsoft YaHei&amp;quot;, &amp;quot;WenQuanYi Micro Hei&amp;quot;, &amp;quot;WenQuanYi Micro Hei Mono&amp;quot;, &amp;quot;WenQuanYi Zen Hei&amp;quot;, &amp;quot;WenQuanYi Zen Hei Mono&amp;quot;, &amp;quot;Noto Sans CJK SC&amp;quot;, &amp;quot;Source Han Sans CN&amp;quot;, SimSun, sans-serif; text-wrap: wrap; background-color: rgb(255, 255, 255);&quot;&gt;1、FMX 框架下，样式是通过名称来标志的。&lt;/p&gt;&lt;p style=&quot;line-height: 1.7; margin-top: 0px; margin-bottom: 1em; color: rgb(51, 51, 51); font-family: &amp;quot;Lucida Grande&amp;quot;, &amp;quot;Helvetica Neue&amp;quot;, Helvetica, Arial, Verdana, &amp;quot;PingFang SC&amp;quot;, &amp;quot;Hiragino Sans GB&amp;quot;, STHeiti, &amp;quot;Microsoft YaHei&amp;quot;, &amp;quot;WenQuanYi Micro Hei&amp;quot;, &amp;quot;WenQuanYi Micro Hei Mono&amp;quot;, &amp;quot;WenQuanYi Zen Hei&amp;quot;, &amp;quot;WenQuanYi Zen Hei Mono&amp;quot;, &amp;quot;Noto Sans CJK SC&amp;quot;, &amp;quot;Source Han Sans CN&amp;quot;, SimSun, sans-serif; text-wrap: wrap; background-color: rgb(255, 255, 255);&quot;&gt;2、GetStyleObject 默认是克隆原始的样式，所以直接修改对象自身的 FResourceLink 实例，不会影响其它样式，如果要修改全部同一类型控件的样式，手动调用控件的 GetStyleObject(false) 来获取样式的原始实例即可，进行调整即可。&lt;/p&gt;&lt;p style=&quot;line-height: 1.7; margin-top: 0px; margin-bottom: 1em; color: rgb(51, 51, 51); font-family: &amp;quot;Lucida Grande&amp;quot;, &amp;quot;Helvetica Neue&amp;quot;, Helvetica, Arial, Verdana, &amp;quot;PingFang SC&amp;quot;, &amp;quot;Hiragino Sans GB&amp;quot;, STHeiti, &amp;quot;Microsoft YaHei&amp;quot;, &amp;quot;WenQuanYi Micro Hei&amp;quot;, &amp;quot;WenQuanYi Micro Hei Mono&amp;quot;, &amp;quot;WenQuanYi Zen Hei&amp;quot;, &amp;quot;WenQuanYi Zen Hei Mono&amp;quot;, &amp;quot;Noto Sans CJK SC&amp;quot;, &amp;quot;Source Han Sans CN&amp;quot;, SimSun, sans-serif; text-wrap: wrap; background-color: rgb(255, 255, 255);&quot;&gt;2、只修改当前实例的特定样式步骤：&lt;/p&gt;&lt;ul style=&quot;box-sizing: border-box; color: rgb(51, 51, 51); font-family: &amp;quot;Lucida Grande&amp;quot;, &amp;quot;Helvetica Neue&amp;quot;, Helvetica, Arial, Verdana, &amp;quot;PingFang SC&amp;quot;, &amp;quot;Hiragino Sans GB&amp;quot;, STHeiti, &amp;quot;Microsoft YaHei&amp;quot;, &amp;quot;WenQuanYi Micro Hei&amp;quot;, &amp;quot;WenQuanYi Micro Hei Mono&amp;quot;, &amp;quot;WenQuanYi Zen Hei&amp;quot;, &amp;quot;WenQuanYi Zen Hei Mono&amp;quot;, &amp;quot;Noto Sans CJK SC&amp;quot;, &amp;quot;Source Han Sans CN&amp;quot;, SimSun, sans-serif; text-wrap: wrap; background-color: rgb(255, 255, 255);&quot; class=&quot; list-paddingleft-2&quot;&gt;&lt;li&gt;&lt;p&gt;通过 ResourceLink 保护属性获取对应的样式对象（受保护成员具体如何访问参考以前的文章）&lt;/p&gt;&lt;/li&gt;&lt;li&gt;&lt;p&gt;直接修改对应的样式对象或者从 ResourceLink 中删除它，然后再创建一个新的 StyleName 同名的对象，添加到 ResourceLink 中&lt;/p&gt;&lt;/li&gt;&lt;li&gt;&lt;p&gt;调用 ApplyStyle 保护方法，来应用样式&lt;/p&gt;&lt;/li&gt;&lt;/ul&gt;&lt;p style=&quot;line-height: 1.7; margin-top: 0px; margin-bottom: 1em; color: rgb(51, 51, 51); font-family: &amp;quot;Lucida Grande&amp;quot;, &amp;quot;Helvetica Neue&amp;quot;, Helvetica, Arial, Verdana, &amp;quot;PingFang SC&amp;quot;, &amp;quot;Hiragino Sans GB&amp;quot;, STHeiti, &amp;quot;Microsoft YaHei&amp;quot;, &amp;quot;WenQuanYi Micro Hei&amp;quot;, &amp;quot;WenQuanYi Micro Hei Mono&amp;quot;, &amp;quot;WenQuanYi Zen Hei&amp;quot;, &amp;quot;WenQuanYi Zen Hei Mono&amp;quot;, &amp;quot;Noto Sans CJK SC&amp;quot;, &amp;quot;Source Han Sans CN&amp;quot;, SimSun, sans-serif; text-wrap: wrap; background-color: rgb(255, 255, 255);&quot;&gt;3、修改全局样式步骤：&lt;/p&gt;&lt;ul style=&quot;box-sizing: border-box; color: rgb(51, 51, 51); font-family: &amp;quot;Lucida Grande&amp;quot;, &amp;quot;Helvetica Neue&amp;quot;, Helvetica, Arial, Verdana, &amp;quot;PingFang SC&amp;quot;, &amp;quot;Hiragino Sans GB&amp;quot;, STHeiti, &amp;quot;Microsoft YaHei&amp;quot;, &amp;quot;WenQuanYi Micro Hei&amp;quot;, &amp;quot;WenQuanYi Micro Hei Mono&amp;quot;, &amp;quot;WenQuanYi Zen Hei&amp;quot;, &amp;quot;WenQuanYi Zen Hei Mono&amp;quot;, &amp;quot;Noto Sans CJK SC&amp;quot;, &amp;quot;Source Han Sans CN&amp;quot;, SimSun, sans-serif; text-wrap: wrap; background-color: rgb(255, 255, 255);&quot; class=&quot; list-paddingleft-2&quot;&gt;&lt;li&gt;&lt;p&gt;通过 GetStyleObject 保护方法，获取原始的对象链接。&lt;/p&gt;&lt;/li&gt;&lt;li&gt;&lt;p&gt;查找对应的样式对象实例&lt;/p&gt;&lt;/li&gt;&lt;li&gt;&lt;p&gt;视需要直接修改对应的样式对象或者从 ResourceLink 中删除它，然后再创建一个新的 StyleName 同名的对象，添加到 ResourceLink 中&lt;/p&gt;&lt;/li&gt;&lt;li&gt;&lt;p&gt;发送 TStyleChangedMessage 消息，这样所有的控件都会更新样式。如果只是当前控件，那么调用下NeedStyleLookup 即可。&lt;/p&gt;&lt;/li&gt;&lt;/ul&gt;&lt;p style=&quot;line-height: 1.7; margin-top: 0px; margin-bottom: 1em; color: rgb(51, 51, 51); font-family: &amp;quot;Lucida Grande&amp;quot;, &amp;quot;Helvetica Neue&amp;quot;, Helvetica, Arial, Verdana, &amp;quot;PingFang SC&amp;quot;, &amp;quot;Hiragino Sans GB&amp;quot;, STHeiti, &amp;quot;Microsoft YaHei&amp;quot;, &amp;quot;WenQuanYi Micro Hei&amp;quot;, &amp;quot;WenQuanYi Micro Hei Mono&amp;quot;, &amp;quot;WenQuanYi Zen Hei&amp;quot;, &amp;quot;WenQuanYi Zen Hei Mono&amp;quot;, &amp;quot;Noto Sans CJK SC&amp;quot;, &amp;quot;Source Han Sans CN&amp;quot;, SimSun, sans-serif; text-wrap: wrap; background-color: rgb(255, 255, 255);&quot;&gt;参考代码：&lt;/p&gt;&lt;pre class=&quot;prism-highlight prism-language-pascal&quot;&gt;uses&amp;nbsp;syste
m.Messaging;
{$R&amp;nbsp;*.fmx}
type
THackedListView=class(TListView)

end;
procedure&amp;nbsp;TForm4.ComboColorBox1Change(Sender:&amp;nbsp;TObject);
var
&amp;nbsp;&amp;nbsp;AStyle,AStyleLink:TFMXObject;
begin
//&amp;nbsp;仅修改&amp;nbsp;ListView1&amp;nbsp;的样式
//&amp;nbsp;&amp;nbsp;AStyleLink:=THackedListView(ListView1).ResourceLink;
//&amp;nbsp;修改全局的&amp;nbsp;TListView&amp;nbsp;样式
&amp;nbsp;&amp;nbsp;AStyleLink:=&amp;nbsp;THackedListView(ListView1).GetStyleObject(false);
&amp;nbsp;&amp;nbsp;AStyle:=AStyleLink.FindStyleResource(&amp;#39;selection&amp;#39;);
&amp;nbsp;&amp;nbsp;if&amp;nbsp;Assigned(AStyle)&amp;nbsp;then
&amp;nbsp;&amp;nbsp;begin
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;if&amp;nbsp;not&amp;nbsp;(AStyle&amp;nbsp;is&amp;nbsp;TColorObject)&amp;nbsp;then
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;begin
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;AStyleLink.RemoveObject(AStyle);
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;AStyle:=TColorObject.Create(AStyleLink);
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;AStyle.StyleName:=&amp;#39;selection&amp;#39;;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;AStyleLink.AddObject(AStyle);
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;end;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;(AStyle&amp;nbsp;as&amp;nbsp;TColorObject).Color:=ComboColorBox1.Color;&amp;nbsp;&amp;nbsp;
//仅修改&amp;nbsp;ListView1&amp;nbsp;的样式
//&amp;nbsp;&amp;nbsp;THackedListView(ListView1).ApplyStyle;
//&amp;nbsp;修改了全局样式，但当前只应用&amp;nbsp;ListView1
//&amp;nbsp;&amp;nbsp;ListView1.NeedStyleLookup;
//&amp;nbsp;修改了全局样式，其它所有&amp;nbsp;ListView&amp;nbsp;都更新
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;TMessageManager.DefaultManager.SendMessage(Sender,TStyleChangedMessage.Create(StyleBook));

&amp;nbsp;&amp;nbsp;end;
end;&lt;/pre&gt;&lt;p&gt;&lt;img class=&quot;ue-image&quot; src=&quot;http://51scm.net/zb_users/upload/2024/07/202407141720925908244664.gif&quot; title=&quot;录屏_选择区域_20220917113911.gif&quot; alt=&quot;录屏_选择区域_20220917113911.gif&quot;/&gt;&lt;/p&gt;&lt;p&gt;&lt;span style=&quot;color: #333333; font-family: &amp;quot;Lucida Grande&amp;quot;, &amp;quot;Helvetica Neue&amp;quot;, Helvetica, Arial, Verdana, &amp;quot;PingFang SC&amp;quot;, &amp;quot;Hiragino Sans GB&amp;quot;, STHeiti, &amp;quot;Microsoft YaHei&amp;quot;, &amp;quot;WenQuanYi Micro Hei&amp;quot;, &amp;quot;WenQuanYi Micro Hei Mono&amp;quot;, &amp;quot;WenQuanYi Zen Hei&amp;quot;, &amp;quot;WenQuanYi Zen Hei Mono&amp;quot;, &amp;quot;Noto Sans CJK SC&amp;quot;, &amp;quot;Source Han Sans CN&amp;quot;, SimSun, sans-serif; text-wrap: wrap; background-color: #FFFFFF;&quot;&gt;上面的代码在 Windows 下是没有问题的，在其它平台，由于在克隆样式时，FMX 采用了不同的策略，所以需要做变动，参考代码如下：&lt;/span&gt;&lt;/p&gt;&lt;pre class=&quot;prism-highlight prism-language-pascal&quot;&gt;type
&amp;nbsp;&amp;nbsp;THackedListView&amp;nbsp;=&amp;nbsp;class(TListView)

&amp;nbsp;&amp;nbsp;end;

procedure&amp;nbsp;ChangeListViewSelectionColor(AListView:&amp;nbsp;TListView;&amp;nbsp;ANewColor:&amp;nbsp;TAlphaColor);&amp;nbsp;overload;
var
&amp;nbsp;&amp;nbsp;AStyle,&amp;nbsp;AStyleLink:&amp;nbsp;TFmxObject;
begin
&amp;nbsp;&amp;nbsp;AStyleLink&amp;nbsp;:=&amp;nbsp;THackedListView(AListView).ResourceLink;
&amp;nbsp;&amp;nbsp;AStyle&amp;nbsp;:=&amp;nbsp;AStyleLink.FindStyleResource(&amp;#39;selection&amp;#39;);
&amp;nbsp;&amp;nbsp;if&amp;nbsp;Assigned(AStyle)&amp;nbsp;then
&amp;nbsp;&amp;nbsp;begin
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;if&amp;nbsp;not(AStyle&amp;nbsp;is&amp;nbsp;TColorObject)&amp;nbsp;then
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;begin
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;AStyleLink.RemoveObject(AStyle);
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;AStyle&amp;nbsp;:=&amp;nbsp;TColorObject.Create(AStyleLink);
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;AStyle.StyleName&amp;nbsp;:=&amp;nbsp;&amp;#39;selection&amp;#39;;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;AStyleLink.AddObject(AStyle);
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;end;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;(AStyle&amp;nbsp;as&amp;nbsp;TColorObject).Color&amp;nbsp;:=&amp;nbsp;ANewColor;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;THackedListView(AListView).ApplyStyle;
&amp;nbsp;&amp;nbsp;end;
end;

procedure&amp;nbsp;ChangeListViewSelectionColor(ANewColor:&amp;nbsp;TAlphaColor);&amp;nbsp;overload;
var
&amp;nbsp;&amp;nbsp;I:&amp;nbsp;Integer;
&amp;nbsp;&amp;nbsp;procedure&amp;nbsp;ApplyColor(AParent:&amp;nbsp;TFmxObject);
&amp;nbsp;&amp;nbsp;var
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;AIndex:&amp;nbsp;Integer;
&amp;nbsp;&amp;nbsp;begin
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;if&amp;nbsp;AParent&amp;nbsp;is&amp;nbsp;TListView&amp;nbsp;then
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;ChangeListViewSelectionColor(TListView(AParent),ANewColor);
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;for&amp;nbsp;AIndex&amp;nbsp;:=&amp;nbsp;0&amp;nbsp;to&amp;nbsp;AParent.ChildrenCount&amp;nbsp;-&amp;nbsp;1&amp;nbsp;do
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;ApplyColor(AParent.Children[AIndex]);
&amp;nbsp;&amp;nbsp;end;

begin
&amp;nbsp;&amp;nbsp;for&amp;nbsp;I&amp;nbsp;:=&amp;nbsp;0&amp;nbsp;to&amp;nbsp;Screen.FormCount&amp;nbsp;-&amp;nbsp;1&amp;nbsp;do
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;ApplyColor(Screen.Forms[I]);
end;&lt;/pre&gt;&lt;p&gt;&lt;span style=&quot;color: #333333; font-family: &amp;quot;Lucida Grande&amp;quot;, &amp;quot;Helvetica Neue&amp;quot;, Helvetica, Arial, Verdana, &amp;quot;PingFang SC&amp;quot;, &amp;quot;Hiragino Sans GB&amp;quot;, STHeiti, &amp;quot;Microsoft YaHei&amp;quot;, &amp;quot;WenQuanYi Micro Hei&amp;quot;, &amp;quot;WenQuanYi Micro Hei Mono&amp;quot;, &amp;quot;WenQuanYi Zen Hei&amp;quot;, &amp;quot;WenQuanYi Zen Hei Mono&amp;quot;, &amp;quot;Noto Sans CJK SC&amp;quot;, &amp;quot;Source Han Sans CN&amp;quot;, SimSun, sans-serif; text-wrap: wrap; background-color: #FFFFFF;&quot;&gt;&lt;/span&gt;&lt;br/&gt;&lt;/p&gt;</description><pubDate>Sun, 14 Jul 2024 10:57:11 +0800</pubDate></item><item><title>Delphi 函数的内部函数在匿名回调函数中无法使用的一种解决办法</title><link>http://51scm.net/?id=5</link><description>&lt;p&gt;&lt;span style=&quot;color: #333333; font-family: &amp;quot;Lucida Grande&amp;quot;, &amp;quot;Helvetica Neue&amp;quot;, Helvetica, Arial, Verdana, &amp;quot;PingFang SC&amp;quot;, &amp;quot;Hiragino Sans GB&amp;quot;, STHeiti, &amp;quot;Microsoft YaHei&amp;quot;, &amp;quot;WenQuanYi Micro Hei&amp;quot;, &amp;quot;WenQuanYi Micro Hei Mono&amp;quot;, &amp;quot;WenQuanYi Zen Hei&amp;quot;, &amp;quot;WenQuanYi Zen Hei Mono&amp;quot;, &amp;quot;Noto Sans CJK SC&amp;quot;, &amp;quot;Source Han Sans CN&amp;quot;, SimSun, sans-serif; text-wrap: wrap; background-color: #FFFFFF;&quot;&gt;这个问题很简单，将对应的函数改写赋值到一个匿名函数变量即可。&lt;/span&gt;&lt;/p&gt;&lt;pre class=&quot;prism-highlight prism-language-pascal&quot;&gt;function&amp;nbsp;test;
&amp;nbsp;&amp;nbsp;function&amp;nbsp;add(x,y:Integer):Integer;
&amp;nbsp;&amp;nbsp;begin
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;Result:=x+y;
&amp;nbsp;&amp;nbsp;end
begin&amp;nbsp;
...
end&lt;/pre&gt;&lt;p&gt;&lt;span style=&quot;color: #333333; font-family: &amp;quot;Lucida Grande&amp;quot;, &amp;quot;Helvetica Neue&amp;quot;, Helvetica, Arial, Verdana, &amp;quot;PingFang SC&amp;quot;, &amp;quot;Hiragino Sans GB&amp;quot;, STHeiti, &amp;quot;Microsoft YaHei&amp;quot;, &amp;quot;WenQuanYi Micro Hei&amp;quot;, &amp;quot;WenQuanYi Micro Hei Mono&amp;quot;, &amp;quot;WenQuanYi Zen Hei&amp;quot;, &amp;quot;WenQuanYi Zen Hei Mono&amp;quot;, &amp;quot;Noto Sans CJK SC&amp;quot;, &amp;quot;Source Han Sans CN&amp;quot;, SimSun, sans-serif; text-wrap: wrap; background-color: #FFFFFF;&quot;&gt;上面的代码改写成：&lt;/span&gt;&lt;/p&gt;&lt;pre class=&quot;prism-highlight prism-language-pascal&quot;&gt;type
&amp;nbsp;&amp;nbsp;TfnAdd=reference&amp;nbsp;to&amp;nbsp;function&amp;nbsp;(x,y:Integer):Integer;
function&amp;nbsp;test;
var
&amp;nbsp;&amp;nbsp;add:TfnAdd;
begin&amp;nbsp;
add:=function&amp;nbsp;add(x,y:Integer):Integer;
&amp;nbsp;&amp;nbsp;begin
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;Result:=x+y;
&amp;nbsp;&amp;nbsp;end;
...
end&lt;/pre&gt;&lt;p&gt;&lt;span style=&quot;color: #333333; font-family: &amp;quot;Lucida Grande&amp;quot;, &amp;quot;Helvetica Neue&amp;quot;, Helvetica, Arial, Verdana, &amp;quot;PingFang SC&amp;quot;, &amp;quot;Hiragino Sans GB&amp;quot;, STHeiti, &amp;quot;Microsoft YaHei&amp;quot;, &amp;quot;WenQuanYi Micro Hei&amp;quot;, &amp;quot;WenQuanYi Micro Hei Mono&amp;quot;, &amp;quot;WenQuanYi Zen Hei&amp;quot;, &amp;quot;WenQuanYi Zen Hei Mono&amp;quot;, &amp;quot;Noto Sans CJK SC&amp;quot;, &amp;quot;Source Han Sans CN&amp;quot;, SimSun, sans-serif; text-wrap: wrap; background-color: #FFFFFF;&quot;&gt;&lt;/span&gt;&lt;span style=&quot;color: #333333; font-family: &amp;quot;Lucida Grande&amp;quot;, &amp;quot;Helvetica Neue&amp;quot;, Helvetica, Arial, Verdana, &amp;quot;PingFang SC&amp;quot;, &amp;quot;Hiragino Sans GB&amp;quot;, STHeiti, &amp;quot;Microsoft YaHei&amp;quot;, &amp;quot;WenQuanYi Micro Hei&amp;quot;, &amp;quot;WenQuanYi Micro Hei Mono&amp;quot;, &amp;quot;WenQuanYi Zen Hei&amp;quot;, &amp;quot;WenQuanYi Zen Hei Mono&amp;quot;, &amp;quot;Noto Sans CJK SC&amp;quot;, &amp;quot;Source Han Sans CN&amp;quot;, SimSun, sans-serif; text-wrap: wrap; background-color: #FFFFFF;&quot;&gt;然后在后面的直接调用 add 即可。&lt;/span&gt;&lt;/p&gt;</description><pubDate>Sat, 13 Jul 2024 09:38:53 +0800</pubDate></item><item><title>高效处理在主线程中显示后台线程处理进度</title><link>http://51scm.net/?id=4</link><description>&lt;p&gt;&lt;span style=&quot;color: #333333; font-family: &amp;quot;Lucida Grande&amp;quot;, &amp;quot;Helvetica Neue&amp;quot;, Helvetica, Arial, Verdana, &amp;quot;PingFang SC&amp;quot;, &amp;quot;Hiragino Sans GB&amp;quot;, STHeiti, &amp;quot;Microsoft YaHei&amp;quot;, &amp;quot;WenQuanYi Micro Hei&amp;quot;, &amp;quot;WenQuanYi Micro Hei Mono&amp;quot;, &amp;quot;WenQuanYi Zen Hei&amp;quot;, &amp;quot;WenQuanYi Zen Hei Mono&amp;quot;, &amp;quot;Noto Sans CJK SC&amp;quot;, &amp;quot;Source Han Sans CN&amp;quot;, SimSun, sans-serif; text-wrap: wrap; background-color: #FFFFFF;&quot;&gt;先看经典的处理方法：&lt;/span&gt;&lt;/p&gt;&lt;pre class=&quot;prism-highlight prism-language-pascal&quot;&gt;TThread.CreateAnonymousThread(
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;procedure
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;var
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;AHint:&amp;nbsp;TZProgressNotify;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;ACount:&amp;nbsp;Integer;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;ATime:&amp;nbsp;Cardinal;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;const
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;PassCount=1000000;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;begin
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;ACount&amp;nbsp;:=&amp;nbsp;0;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;ATime&amp;nbsp;:=&amp;nbsp;TThread.GetTickCount;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;while&amp;nbsp;(not&amp;nbsp;Application.Terminated)&amp;nbsp;and&amp;nbsp;(ACount&amp;nbsp;&amp;lt;&amp;nbsp;PassCount)&amp;nbsp;do
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;begin
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;AHint.Progress&amp;nbsp;:=&amp;nbsp;ACount*100&amp;nbsp;div&amp;nbsp;PassCount&amp;nbsp;;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;AHint.HintText&amp;nbsp;:=&amp;nbsp;ACount.ToString;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;Inc(ACount);&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;TThread.Synchronize(nil,
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;procedure
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;begin
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;FProgress.Update(AHint);
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;end
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;);
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;FProgress.Update(AHint);
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;end;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;AHint.HintText&amp;nbsp;:=&amp;nbsp;(TThread.GetTickCount&amp;nbsp;-&amp;nbsp;ATime).ToString&amp;nbsp;+&amp;nbsp;&amp;#39;ms&amp;#39;;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;FProgress.Update(AHint);
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;end).Start;&lt;/pre&gt;&lt;p style=&quot;line-height: 1.7; margin-top: 0px; margin-bottom: 1em; color: rgb(51, 51, 51); font-family: &amp;quot;Lucida Grande&amp;quot;, &amp;quot;Helvetica Neue&amp;quot;, Helvetica, Arial, Verdana, &amp;quot;PingFang SC&amp;quot;, &amp;quot;Hiragino Sans GB&amp;quot;, STHeiti, &amp;quot;Microsoft YaHei&amp;quot;, &amp;quot;WenQuanYi Micro Hei&amp;quot;, &amp;quot;WenQuanYi Micro Hei Mono&amp;quot;, &amp;quot;WenQuanYi Zen Hei&amp;quot;, &amp;quot;WenQuanYi Zen Hei Mono&amp;quot;, &amp;quot;Noto Sans CJK SC&amp;quot;, &amp;quot;Source Han Sans CN&amp;quot;, SimSun, sans-serif; text-wrap: wrap; background-color: rgb(255, 255, 255);&quot;&gt;我们需要更新进度时，将其切换到主线程，并更新进度显示。我们测试显示用了32735ms，也就是说100万次进度更新，用了约33秒。&lt;/p&gt;&lt;p style=&quot;line-height: 1.7; margin-top: 0px; margin-bottom: 1em; color: rgb(51, 51, 51); font-family: &amp;quot;Lucida Grande&amp;quot;, &amp;quot;Helvetica Neue&amp;quot;, Helvetica, Arial, Verdana, &amp;quot;PingFang SC&amp;quot;, &amp;quot;Hiragino Sans GB&amp;quot;, STHeiti, &amp;quot;Microsoft YaHei&amp;quot;, &amp;quot;WenQuanYi Micro Hei&amp;quot;, &amp;quot;WenQuanYi Micro Hei Mono&amp;quot;, &amp;quot;WenQuanYi Zen Hei&amp;quot;, &amp;quot;WenQuanYi Zen Hei Mono&amp;quot;, &amp;quot;Noto Sans CJK SC&amp;quot;, &amp;quot;Source Han Sans CN&amp;quot;, SimSun, sans-serif; text-wrap: wrap; background-color: rgb(255, 255, 255);&quot;&gt;接下来我们来看下优化后的代码：&lt;/p&gt;&lt;pre class=&quot;prism-highlight prism-language-pascal&quot;&gt;TThread.CreateAnonymousThread(
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;procedure
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;var
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;AHint:&amp;nbsp;TZProgressNotify;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;ACount:&amp;nbsp;Integer;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;ATime:&amp;nbsp;Cardinal;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;const
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;PassCount=1000000;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;begin
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;ACount&amp;nbsp;:=&amp;nbsp;0;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;ATime&amp;nbsp;:=&amp;nbsp;TThread.GetTickCount;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;while&amp;nbsp;(not&amp;nbsp;Application.Terminated)&amp;nbsp;and&amp;nbsp;(ACount&amp;nbsp;&amp;lt;&amp;nbsp;PassCount)&amp;nbsp;do
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;begin
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;AHint.Progress&amp;nbsp;:=&amp;nbsp;ACount*100&amp;nbsp;div&amp;nbsp;PassCount&amp;nbsp;;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;AHint.HintText&amp;nbsp;:=&amp;nbsp;ACount.ToString;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;Inc(ACount);&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;FProgress.Update(AHint);
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;end;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;AHint.HintText&amp;nbsp;:=&amp;nbsp;(TThread.GetTickCount&amp;nbsp;-&amp;nbsp;ATime).ToString&amp;nbsp;+&amp;nbsp;&amp;#39;ms&amp;#39;;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;FProgress.Update(AHint);
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;end).Start;&lt;/pre&gt;&lt;p&gt;&lt;span style=&quot;color: #333333; font-family: &amp;quot;Lucida Grande&amp;quot;, &amp;quot;Helvetica Neue&amp;quot;, Helvetica, Arial, Verdana, &amp;quot;PingFang SC&amp;quot;, &amp;quot;Hiragino Sans GB&amp;quot;, STHeiti, &amp;quot;Microsoft YaHei&amp;quot;, &amp;quot;WenQuanYi Micro Hei&amp;quot;, &amp;quot;WenQuanYi Micro Hei Mono&amp;quot;, &amp;quot;WenQuanYi Zen Hei&amp;quot;, &amp;quot;WenQuanYi Zen Hei Mono&amp;quot;, &amp;quot;Noto Sans CJK SC&amp;quot;, &amp;quot;Source Han Sans CN&amp;quot;, SimSun, sans-serif; text-wrap: wrap; background-color: #FFFFFF;&quot;&gt;&lt;/span&gt;&lt;/p&gt;&lt;p style=&quot;line-height: 1.7; margin-top: 0px; margin-bottom: 1em; color: rgb(51, 51, 51); font-family: &amp;quot;Lucida Grande&amp;quot;, &amp;quot;Helvetica Neue&amp;quot;, Helvetica, Arial, Verdana, &amp;quot;PingFang SC&amp;quot;, &amp;quot;Hiragino Sans GB&amp;quot;, STHeiti, &amp;quot;Microsoft YaHei&amp;quot;, &amp;quot;WenQuanYi Micro Hei&amp;quot;, &amp;quot;WenQuanYi Micro Hei Mono&amp;quot;, &amp;quot;WenQuanYi Zen Hei&amp;quot;, &amp;quot;WenQuanYi Zen Hei Mono&amp;quot;, &amp;quot;Noto Sans CJK SC&amp;quot;, &amp;quot;Source Han Sans CN&amp;quot;, SimSun, sans-serif; text-wrap: wrap; background-color: rgb(255, 255, 255);&quot;&gt;对的，你没看错，我们将 FProgress.Update 直接在后台线程调用了。我们对其代码进行了逻辑隔离，实测 100 万次进度更新，用时 78 毫秒。&lt;/p&gt;&lt;p style=&quot;line-height: 1.7; margin-top: 0px; margin-bottom: 1em; color: rgb(51, 51, 51); font-family: &amp;quot;Lucida Grande&amp;quot;, &amp;quot;Helvetica Neue&amp;quot;, Helvetica, Arial, Verdana, &amp;quot;PingFang SC&amp;quot;, &amp;quot;Hiragino Sans GB&amp;quot;, STHeiti, &amp;quot;Microsoft YaHei&amp;quot;, &amp;quot;WenQuanYi Micro Hei&amp;quot;, &amp;quot;WenQuanYi Micro Hei Mono&amp;quot;, &amp;quot;WenQuanYi Zen Hei&amp;quot;, &amp;quot;WenQuanYi Zen Hei Mono&amp;quot;, &amp;quot;Noto Sans CJK SC&amp;quot;, &amp;quot;Source Han Sans CN&amp;quot;, SimSun, sans-serif; text-wrap: wrap; background-color: rgb(255, 255, 255);&quot;&gt;我们来看一下具体的实现：&lt;/p&gt;&lt;pre class=&quot;prism-highlight prism-language-pascal&quot;&gt;type
&amp;nbsp;&amp;nbsp;TZProgressNotify&amp;nbsp;=&amp;nbsp;record
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;Progress:&amp;nbsp;Integer;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;HintText:&amp;nbsp;String;
&amp;nbsp;&amp;nbsp;end;

TZMainThreadUpdator&amp;nbsp;&amp;lt;&amp;nbsp;T:&amp;nbsp;record&amp;nbsp;&amp;gt;=&amp;nbsp;record
private
const
&amp;nbsp;&amp;nbsp;FLAG_READING&amp;nbsp;=&amp;nbsp;Integer($80000000);
var
&amp;nbsp;&amp;nbsp;FBuffers:&amp;nbsp;array&amp;nbsp;[0&amp;nbsp;..&amp;nbsp;1]&amp;nbsp;of&amp;nbsp;T;
&amp;nbsp;&amp;nbsp;FActiveIndex,&amp;nbsp;FUpdateRefCount:&amp;nbsp;Integer;
public
&amp;nbsp;&amp;nbsp;procedure&amp;nbsp;Update(const&amp;nbsp;AValue:&amp;nbsp;T);
&amp;nbsp;&amp;nbsp;function&amp;nbsp;GetData:&amp;nbsp;T;overload;
&amp;nbsp;&amp;nbsp;procedure&amp;nbsp;GetData(var&amp;nbsp;AValue:&amp;nbsp;T);overload;
&amp;nbsp;&amp;nbsp;property&amp;nbsp;Data:&amp;nbsp;T&amp;nbsp;read&amp;nbsp;GetData;
end;

{&amp;nbsp;TZMainThreadUpdator&amp;lt;T&amp;gt;&amp;nbsp;}

procedure&amp;nbsp;TZMainThreadUpdator&amp;lt;T&amp;gt;.GetData(var&amp;nbsp;AValue:&amp;nbsp;T);
//&amp;nbsp;值复制可能会引起冲突，我们需要避免在值复制时，外部更新，所以将&amp;nbsp;FActiveIndex&amp;nbsp;加入标志位
var
&amp;nbsp;&amp;nbsp;ABufferIndex:&amp;nbsp;Integer;
begin
&amp;nbsp;&amp;nbsp;Assert(MainThreadId&amp;nbsp;=&amp;nbsp;TThread.Current.ThreadID,
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;#39;GetData&amp;nbsp;must&amp;nbsp;invoke&amp;nbsp;in&amp;nbsp;main&amp;nbsp;thread&amp;#39;);
&amp;nbsp;&amp;nbsp;//设置读取中标记位，设置后，Update不会更新&amp;nbsp;FActiveIndex&amp;nbsp;的值
&amp;nbsp;&amp;nbsp;repeat
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;ABufferIndex&amp;nbsp;:=&amp;nbsp;FActiveIndex;
&amp;nbsp;&amp;nbsp;until&amp;nbsp;AtomicCmpExchange(FActiveIndex,&amp;nbsp;ABufferIndex&amp;nbsp;or&amp;nbsp;FLAG_READING,
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;ABufferIndex)&amp;nbsp;=&amp;nbsp;ABufferIndex;
&amp;nbsp;&amp;nbsp;AValue&amp;nbsp;:=&amp;nbsp;FBuffers[ABufferIndex];
&amp;nbsp;&amp;nbsp;//允许后续的&amp;nbsp;Update&amp;nbsp;更新&amp;nbsp;FActiveIndex&amp;nbsp;的值以体现最新的进度
&amp;nbsp;&amp;nbsp;AtomicExchange(FActiveIndex,&amp;nbsp;ABufferIndex);
end;

function&amp;nbsp;TZMainThreadUpdator&amp;lt;T&amp;gt;.GetData:&amp;nbsp;T;
begin
&amp;nbsp;&amp;nbsp;GetData(Result);
end;

procedure&amp;nbsp;TZMainThreadUpdator&amp;lt;T&amp;gt;.Update(const&amp;nbsp;AValue:&amp;nbsp;T);
var
&amp;nbsp;&amp;nbsp;ABufferIndex:&amp;nbsp;Integer;
begin
&amp;nbsp;&amp;nbsp;ABufferIndex&amp;nbsp;:=&amp;nbsp;AtomicIncrement(FUpdateRefCount);
&amp;nbsp;&amp;nbsp;try
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;//&amp;nbsp;增加计数，如果有多个同时提交更新，只有第一个会保留，剩下的会丢弃
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;if&amp;nbsp;ABufferIndex&amp;nbsp;=&amp;nbsp;1&amp;nbsp;then
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;begin
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;//&amp;nbsp;多个线程同时更新，只保留第一个更新线程的结果，避免使用锁
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;ABufferIndex&amp;nbsp;:=&amp;nbsp;(FActiveIndex&amp;nbsp;+&amp;nbsp;1)&amp;nbsp;and&amp;nbsp;$1;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;FBuffers[ABufferIndex]&amp;nbsp;:=&amp;nbsp;AValue;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;//&amp;nbsp;如果&amp;nbsp;FActiveIndex&amp;nbsp;不处于读状态，则更新，否则忽略更新，可以增加额外的标记来记录这个情况，然后在读取的时候清楚这一标记，本版本不做处理
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;AtomicCmpExchange(FActiveIndex,&amp;nbsp;ABufferIndex,&amp;nbsp;FActiveIndex&amp;nbsp;and&amp;nbsp;$1);
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;end;
&amp;nbsp;&amp;nbsp;finally
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;AtomicDecrement(FUpdateRefCount);
&amp;nbsp;&amp;nbsp;end;
end;&lt;/pre&gt;&lt;p&gt;&lt;br/&gt;&lt;/p&gt;</description><pubDate>Thu, 11 Jul 2024 10:38:55 +0800</pubDate></item><item><title>Ｄelphi 泛型中数据内容比较</title><link>http://51scm.net/?id=3</link><description>&lt;p style=&quot;line-height: 1.7; margin-top: -0.3em; margin-bottom: 1em; color: rgb(51, 51, 51); font-family: &amp;quot;Lucida Grande&amp;quot;, &amp;quot;Helvetica Neue&amp;quot;, Helvetica, Arial, Verdana, &amp;quot;PingFang SC&amp;quot;, &amp;quot;Hiragino Sans GB&amp;quot;, STHeiti, &amp;quot;Microsoft YaHei&amp;quot;, &amp;quot;WenQuanYi Micro Hei&amp;quot;, &amp;quot;WenQuanYi Micro Hei Mono&amp;quot;, &amp;quot;WenQuanYi Zen Hei&amp;quot;, &amp;quot;WenQuanYi Zen Hei Mono&amp;quot;, &amp;quot;Noto Sans CJK SC&amp;quot;, &amp;quot;Source Han Sans CN&amp;quot;, SimSun, sans-serif; text-wrap: wrap; background-color: rgb(255, 255, 255);&quot;&gt;第一：你需要引入 System.Generics.Defaults 单元，系统默认实现的比较方法，都在该单元定义。&lt;/p&gt;&lt;p style=&quot;line-height: 1.7; margin-top: 0px; margin-bottom: 1em; color: rgb(51, 51, 51); font-family: &amp;quot;Lucida Grande&amp;quot;, &amp;quot;Helvetica Neue&amp;quot;, Helvetica, Arial, Verdana, &amp;quot;PingFang SC&amp;quot;, &amp;quot;Hiragino Sans GB&amp;quot;, STHeiti, &amp;quot;Microsoft YaHei&amp;quot;, &amp;quot;WenQuanYi Micro Hei&amp;quot;, &amp;quot;WenQuanYi Micro Hei Mono&amp;quot;, &amp;quot;WenQuanYi Zen Hei&amp;quot;, &amp;quot;WenQuanYi Zen Hei Mono&amp;quot;, &amp;quot;Noto Sans CJK SC&amp;quot;, &amp;quot;Source Han Sans CN&amp;quot;, SimSun, sans-serif; text-wrap: wrap; background-color: rgb(255, 255, 255);&quot;&gt;第二：你要明确下你的需求，是只比较相等就可以，还是要比较大小。&lt;/p&gt;&lt;ul style=&quot;box-sizing: border-box; color: rgb(51, 51, 51); font-family: &amp;quot;Lucida Grande&amp;quot;, &amp;quot;Helvetica Neue&amp;quot;, Helvetica, Arial, Verdana, &amp;quot;PingFang SC&amp;quot;, &amp;quot;Hiragino Sans GB&amp;quot;, STHeiti, &amp;quot;Microsoft YaHei&amp;quot;, &amp;quot;WenQuanYi Micro Hei&amp;quot;, &amp;quot;WenQuanYi Micro Hei Mono&amp;quot;, &amp;quot;WenQuanYi Zen Hei&amp;quot;, &amp;quot;WenQuanYi Zen Hei Mono&amp;quot;, &amp;quot;Noto Sans CJK SC&amp;quot;, &amp;quot;Source Han Sans CN&amp;quot;, SimSun, sans-serif; text-wrap: wrap; background-color: rgb(255, 255, 255);&quot; class=&quot; list-paddingleft-2&quot;&gt;&lt;li&gt;&lt;p&gt;IEqualityComparer&amp;lt;T&amp;gt; 是用来比较两个值是否相等的接口&lt;/p&gt;&lt;/li&gt;&lt;li&gt;&lt;p&gt;IComparer&amp;lt;T&amp;gt; 是用来比较两个值大小的接口&lt;/p&gt;&lt;/li&gt;&lt;/ul&gt;&lt;p style=&quot;line-height: 1.7; margin-top: 0px; margin-bottom: 1em; color: rgb(51, 51, 51); font-family: &amp;quot;Lucida Grande&amp;quot;, &amp;quot;Helvetica Neue&amp;quot;, Helvetica, Arial, Verdana, &amp;quot;PingFang SC&amp;quot;, &amp;quot;Hiragino Sans GB&amp;quot;, STHeiti, &amp;quot;Microsoft YaHei&amp;quot;, &amp;quot;WenQuanYi Micro Hei&amp;quot;, &amp;quot;WenQuanYi Micro Hei Mono&amp;quot;, &amp;quot;WenQuanYi Zen Hei&amp;quot;, &amp;quot;WenQuanYi Zen Hei Mono&amp;quot;, &amp;quot;Noto Sans CJK SC&amp;quot;, &amp;quot;Source Han Sans CN&amp;quot;, SimSun, sans-serif; text-wrap: wrap; background-color: rgb(255, 255, 255);&quot;&gt;第三：确定是否要自己实现比较函数还是使用默认的比较函数，如果使用默认的比较函数：&lt;/p&gt;&lt;ul style=&quot;box-sizing: border-box; color: rgb(51, 51, 51); font-family: &amp;quot;Lucida Grande&amp;quot;, &amp;quot;Helvetica Neue&amp;quot;, Helvetica, Arial, Verdana, &amp;quot;PingFang SC&amp;quot;, &amp;quot;Hiragino Sans GB&amp;quot;, STHeiti, &amp;quot;Microsoft YaHei&amp;quot;, &amp;quot;WenQuanYi Micro Hei&amp;quot;, &amp;quot;WenQuanYi Micro Hei Mono&amp;quot;, &amp;quot;WenQuanYi Zen Hei&amp;quot;, &amp;quot;WenQuanYi Zen Hei Mono&amp;quot;, &amp;quot;Noto Sans CJK SC&amp;quot;, &amp;quot;Source Han Sans CN&amp;quot;, SimSun, sans-serif; text-wrap: wrap; background-color: rgb(255, 255, 255);&quot; class=&quot; list-paddingleft-2&quot;&gt;&lt;li&gt;&lt;p&gt;IEqualityComparer&amp;lt;T&amp;gt; 的值取 TEqualityComparer&amp;lt;T&amp;gt;.Default&lt;/p&gt;&lt;/li&gt;&lt;li&gt;&lt;p&gt;IComparer&amp;lt;T&amp;gt; 的值取 TEqualityComparer&amp;lt;T&amp;gt;.Default&lt;/p&gt;&lt;/li&gt;&lt;/ul&gt;&lt;p style=&quot;line-height: 1.7; margin-top: 0px; margin-bottom: 1em; color: rgb(51, 51, 51); font-family: &amp;quot;Lucida Grande&amp;quot;, &amp;quot;Helvetica Neue&amp;quot;, Helvetica, Arial, Verdana, &amp;quot;PingFang SC&amp;quot;, &amp;quot;Hiragino Sans GB&amp;quot;, STHeiti, &amp;quot;Microsoft YaHei&amp;quot;, &amp;quot;WenQuanYi Micro Hei&amp;quot;, &amp;quot;WenQuanYi Micro Hei Mono&amp;quot;, &amp;quot;WenQuanYi Zen Hei&amp;quot;, &amp;quot;WenQuanYi Zen Hei Mono&amp;quot;, &amp;quot;Noto Sans CJK SC&amp;quot;, &amp;quot;Source Han Sans CN&amp;quot;, SimSun, sans-serif; text-wrap: wrap; background-color: rgb(255, 255, 255);&quot;&gt;如果要实现自己的比较函数，则可以使用预置的封装加一个匿名函数实现：&lt;/p&gt;&lt;ul style=&quot;box-sizing: border-box; color: rgb(51, 51, 51); font-family: &amp;quot;Lucida Grande&amp;quot;, &amp;quot;Helvetica Neue&amp;quot;, Helvetica, Arial, Verdana, &amp;quot;PingFang SC&amp;quot;, &amp;quot;Hiragino Sans GB&amp;quot;, STHeiti, &amp;quot;Microsoft YaHei&amp;quot;, &amp;quot;WenQuanYi Micro Hei&amp;quot;, &amp;quot;WenQuanYi Micro Hei Mono&amp;quot;, &amp;quot;WenQuanYi Zen Hei&amp;quot;, &amp;quot;WenQuanYi Zen Hei Mono&amp;quot;, &amp;quot;Noto Sans CJK SC&amp;quot;, &amp;quot;Source Han Sans CN&amp;quot;, SimSun, sans-serif; text-wrap: wrap; background-color: rgb(255, 255, 255);&quot; class=&quot; list-paddingleft-2&quot;&gt;&lt;li&gt;&lt;p&gt;IEqualityComparer&amp;lt;T&amp;gt; 的值取 TEqualityComparer&amp;lt;T&amp;gt;.Construct(…)&lt;/p&gt;&lt;/li&gt;&lt;li&gt;&lt;p&gt;IComparer&amp;lt;T&amp;gt; 的值取 TEqualityComparer&amp;lt;T&amp;gt;.Construct(…)&lt;/p&gt;&lt;/li&gt;&lt;/ul&gt;&lt;p style=&quot;line-height: 1.7; margin-top: 0px; margin-bottom: 1em; color: rgb(51, 51, 51); font-family: &amp;quot;Lucida Grande&amp;quot;, &amp;quot;Helvetica Neue&amp;quot;, Helvetica, Arial, Verdana, &amp;quot;PingFang SC&amp;quot;, &amp;quot;Hiragino Sans GB&amp;quot;, STHeiti, &amp;quot;Microsoft YaHei&amp;quot;, &amp;quot;WenQuanYi Micro Hei&amp;quot;, &amp;quot;WenQuanYi Micro Hei Mono&amp;quot;, &amp;quot;WenQuanYi Zen Hei&amp;quot;, &amp;quot;WenQuanYi Zen Hei Mono&amp;quot;, &amp;quot;Noto Sans CJK SC&amp;quot;, &amp;quot;Source Han Sans CN&amp;quot;, SimSun, sans-serif; text-wrap: wrap; background-color: rgb(255, 255, 255);&quot;&gt;执行实现比较时，使用对应的 IComparer&amp;lt;T&amp;gt;.Compare 或 IEqualityComparer&amp;lt;T&amp;gt;.Equals 来比较。&lt;/p&gt;</description><pubDate>Wed, 10 Jul 2024 11:27:41 +0800</pubDate></item></channel></rss>