Alcinoe 组件库,由 Zeus64 开发,是一个为 Delphi 提供的开源视觉和非视觉组件库。
完整的 OpenGL 视频播放器、WebRTC Delphi 封装、原生 iOS/Android TEdit 组件、改进的 FireMonkey 控件、Firebase 云消息推送、Android/iOS Facebook SDK 登录、Json/Bson 解析器、ImageMagick 封装、MongoDB 客户端。
Alcinoe 兼容 Delphi Rio 10.3.3 和 Delphi Sydney 10.4.2。
https://github.com/Zeus64/alcinoe
Delphi Alexandria 11.1 支持 MOD 下载(已移除)。
Alcinoe 现在已完全兼容 Delphi Athens 12.3。.
安装 Alcinoe
如果您计划在设计时使用任何 Alcinoe 视觉组件,则您无需安装任何内容,只需将 {alcinoe_rootdir}\source 添加到您的项目的搜索路径中。
如果您计划在设计时使用视觉组件,则需要安装 BPL。 启动 Delphi,进入“组件”>“安装包...”,然后选择位于 {alcinoe_rootdir}\lib\bpl\alcinoe\Win32\sydney\Alcinoe_sydney.bpl 的 BPL 文件(如果您使用的是 Delphi Sydney 版本,否则请选择与您的 Delphi 版本对应的目录)。 您仍然需要将 {alcinoe_rootdir}\source 添加到您的搜索路径中。
Alcinoe 也会对原始 Delphi 源代码进行一些改进。 这样,您需要进入 {alcinoe_rootdir}\embarcadero\sydney\10_4_2 目录,并运行 update.bat 来获取并修补原始 Delphi 源代码。 该批处理文件假定原始源代码位于 “c:\Program Files (x86)\Embarcadero\Studio\21.0\source”,并且您已将 GIT 添加到您的路径中。 在批处理文件复制并修补 Delphi 源代码后,您需要在您的项目搜索路径中包含此源代码。
为了支持更多库使用 Java 1.8 的特性(例如 webRTC、exoplayer 等),我们需要进行反编译(Desugaring,反编译允许您在构建过程中,通过将新的字节码和语言 API 替换为旧的,在较旧的设备上使用这些特性)。 使用 d8.bat(dx.bat 的替代品)时,反编译默认已启用。 因此,您现在可以使用大多数最新的语言更改,同时针对较旧的设备。 在 Embarcadero 切换到 D8.bat 之前,我们需要将 DX.bat 设置为 D8.bat 的“代理”。为此,只需将原始的 DX.bat(我的位于 c:\SDKs\android\build-tools\30.0.3\d8.bat)替换为位于 {alcinoe_rootdir}\tools\D8Proxy\dx.bat 的文件。 更多详细信息请参考:https://quality.embarcadero.com/browse/RSP-24155
用于 FireMonkey 的完整 OpenGL 视频播放器
ALVideoPlayer 会将视频渲染到纹理 (TEXTURE) 上。 这非常重要,因为您可以完全将视频集成到 Delphi 窗体中,并且可以在其上方放置任何控件,因为它支持 Z 顺序。 官方 Delphi 视频播放器只是在窗体顶部的本机视频播放器窗口,因此不支持 Z 顺序。
在 Android 上,我使用 ExoPlayer。 ExoPlayer 支持 MediaPlayer 不支持的功能,例如动态自适应 HTTP 传输 (DASH)、HLS、SmoothStreaming 和通用加密。 它的设计易于定制和扩展。 在 iOS 上,我使用 AVPlayer,它也支持与 ExoPlayer 相同的 HLS 功能。
FireMonkey 视频播放器 FireMonkey 视频播放器 FireMonkey 视频播放器
WebRTC Delphi 封装
WebRTC(Web 实时通信)是一种技术,它使 Web 应用程序和网站能够捕获并可选地流式传输音频和/或视频媒体,以及在浏览器和移动应用程序之间交换任意数据,而无需中间环节。WebRTC 组成的标准集使得可以进行点对点的数据共享和视频会议,而无需用户安装插件或其他第三方软件。
TALWebRTC 组件使您可以轻松地将视频和音频聊天功能添加到您的应用程序中,从而开启全新的交互世界。
Delphi WebRTC 封装
Firemonkey 原生 iOS/Android TEdit 和 TMemo 组件
目标是,当某个控件的功能变得难以实现时,将 FireMonkey 控件与原生平台控件相结合(例如,Web 浏览器、编辑框、记事本、日期选择器等)。但这并不是为了为不同的平台创建多个不同的表单,例如 http://www.turbococoa.com/ 提供的方案(但这在某种程度上也是一个不错的替代方案,您可以根据自己的需要进行选择)。
在 Delphi (berlin) 中,已经存在相当完善的 iOS 平台控件,但几乎没有 Android 平台控件,因此我开始构建原生 Android/iOS 控件,例如 TEdit/TMemo。这些控件的工作方式类似于放置在表单顶部的窗口(因此,它们不能与 FireMonkey 控件进行 Z 顺序调整)。
Drawing Drawing
Drawing
快速/双缓冲的 FireMonkey 控件,具有原生绘制功能。
Rectangle
Circle
Text (也可以在 iOS/android/win/macOS 上绘制 HTML 文本)
Glyph
等。
TALRectangle
TALRectangle
这个事实
绘制 FireMonkey 控件有时可能很慢,或者说,速度不够快,无法实现流畅的滚动。 例如,如果只是查看一个带有圆角的 TRectangle,绘制过程可能需要 3 毫秒! 如果屏幕上有大约 20 个可见的 TRectangle,那么刷新整个屏幕就需要大约 60 毫秒(通常你不仅有 TRectangle,还有 TLabel、TCheckbox 等)。 刷新屏幕需要 100 毫秒,这意味着你只能达到大约 10 帧每秒(实际上会更少),因此滚动效果无法流畅 🙁
解决方案
我不想重构 FireMonkey 控件,那是一项非常庞大的工作,而是尝试寻找一个中间解决方案。 我通过为 FireMonkey 控件添加“双缓冲”属性找到了这个解决方案。 这样,我不再为每个滚动框的像素移动而重复绘制控件,而是首先将控件绘制到一个“缓冲区”上,该缓冲区直接存储在 GPU 内存中(通过 TTexture),当系统要求我重新绘制控件时,我不再调用绘制算法,而是简单地重绘该缓冲区 TTexture。
结果
如前所述,绘制一个带有圆角的简单 TRectangle 需要 3 毫秒。 使用我的双缓冲属性,现在只需要大约 0.1 毫秒! 现在滚动效果看起来更流畅了!
OpenGL draw => 替换为原生的 iOS/Android 绘图。
大部分基本形状(如 TRectangle、TCircle 等)使用 OpenGL 绘图,效率不高。例如,在 OpenGL 下绘制一个圆实际上需要绘制 50 个三角形。这通常会导致质量问题:https://quality.embarcadero.com/browse/RSP-15206。对于圆角矩形,情况更糟,因为它需要先计算路径,然后再绘制(比绘制圆形慢得多)。
另一个问题是,所有这些绘图都依赖于 Form.quality。如果将 form.quality 设置为 highquality,那么在画布上执行的所有操作都将进行多采样,例如绘制图像,这可能会导致问题,因为图像会被抗锯齿处理。如果将 form.quality 设置为 highperformance,则绘制效果会非常粗糙(没有抗锯齿)。
为了解决这个问题,我使用 NATIVE ANDROID/IOS API 构建了控件的缓冲区。这样,我们可以在保证高质量的同时,以高速度进行绘制,并且不依赖于 form.quality。
TALCircle
改进的 FireMonkey 控件
ScrollBox
TabControl
RangeTrackBar
RangeTrackBar
FireMonkey 视频播放器 FireMonkey 视频播放器 FireMonkey 视频播放器
Confetti Falling Animation
ALConfetti 是一个原生的 Delphi 库,用于创建可配置的高性能飘落式彩带动画。
彩带
Firebase 云消息传递
一种跨平台方法,使用 Firebase Cloud Messaging (FCM) 接收推送通知。通过 FCM,您可以通知客户端应用程序,有新的电子邮件或其他数据可供同步。您可以发送通知消息来提高用户参与度和留存率。对于诸如即时消息之类的用例,一条消息可以将最多 4KB 的数据传输到客户端应用程序。
Android/iOS VKontakte/Facebook SDK 登录
Android 平台的 VKontakte/Facebook SDK 允许用户使用 VKontakte/Facebook 登录您的应用程序。当用户使用 VKontakte/Facebook 登录您的应用程序时,他们可以授予您的应用程序权限,以便您可以在他们的 VKontakte/Facebook 账户上检索信息或执行操作。
Android/iOS 平台的照片编辑滤镜
使用 TALColorAdjustEffect,只需一键即可自动增强照片,让您的照片在几分钟内变得美丽而富有表现力!
FireMonkey 视频播放器
JSON 解析器
TALJsonDocument 是一个用于 JSON / BSON 数据格式的 Delphi 解析器/写入器。它支持 DOM 和 SAX 解析器(注意,一个更好的名称可能是 SAJ,即 Simple API for JSON,而不是 SAX,即 Simple API for XML,但由于 SAX 的概念广为人知,我保留了这个名称),支持 BSON 格式,并且使用与 TALXMLDocument / TXMLDocument 相似的语法。TALJsonDocument 还可以将 JSON / Bson 数据导出到 TALStringList 中。
在处理解析某些(文本)内容时,通常会考虑两种方向。在 JSON 世界中,您通常需要选择:
一个 DOM 解析器,它会创建一个内存中的对象树结构,用于映射 JSON 内容。
一个 SAX 解析器,它会读取 JSON 内容,然后为每个 JSON 内容元素调用预定义的事件。
实际上,DOM 解析器在内部使用一个 SAX 解析器来读取 JSON 内容。因此,由于对象创建和属性初始化带来的开销,DOM 解析器通常比 SAX 解析器慢三到五倍(并且使用更多的内存来存储所有节点)。但是,DOM 解析器在处理数据方面功能更强大:一旦数据映射到原生对象,代码可以随时访问任何节点,而基于 SAX 的访问需要再次读取整个 JSON 内容。
大多数 Delphi 中可用的 JSON 解析器都采用类似于 DOM 的方法。例如,自 Delphi 2010 以来包含的 DBXJSON 单元或 SuperObject 库会为每个 JSON 节点创建一个类实例。为了实现最佳速度,TALJsonDocument 实现了 DOM 解析器,也实现了 SAX 解析器。
TALJsonDocument 还可以支持 JSON 源文件中的注释,这是一种对 JSON 规范的扩展。
TALJsonDocument 的语法与 TALXMLdocument / TXMLDocument 非常相似。
TALJsonDocument 有两个变体:TALJsonDocument,它基于 ansiString(即 UTF-8),以及 TALJsonDocumentU,它基于 unicode 字符串(即 UTF-16)。
示例:
{
_id: 1, // comments
name: { first: “John”, last: “Backus” },
birth: new Date(‘1999-10-21T21:04:54.234Z’),
contribs: [ “Fortran”, “ALGOL”, “Backus-Naur Form”, “FP” ],
awards: [
{ award: “National Medal of Science”,
year: 1975,
by: “National Science Foundation” },
{ award: “图灵奖”,
year: 1977,
by: “ACM” }
],
spouse: “”,
address: {},
phones: []
}
要访问文档节点:
MyJsonDoc.loadFromJson(AJsonStr, False);
MyJsonDoc.ParseOptions := [poAllowComments]; // 允许在 JSON 源文件中包含注释
MyJsonDoc.childnodes['_id'].int32;
MyJsonDoc.childnodes['name'].childnodes['first'].text;
MyJsonDoc.childnodes['name'].childnodes['last'].text;
MyJsonDoc.childnodes['birth'].datetime;
for i := 0 to MyJsonDoc.childnodes['contribs'].ChildNodes.count – 1 do
MyJsonDoc.childnodes['contribs'].childnodes[i].text;
for i := 0 to MyJsonDoc.childnodes['awards'].ChildNodes.count – 1 do begin
MyJsonDoc.childnodes['awards'].childnodes[i].childnodes['award'].text;
MyJsonDoc.childnodes['awards'].childnodes[i].childnodes['year'].text;
MyJsonDoc.childnodes['awards'].childnodes[i].childnodes['by'].text;
end;
或者,如果您不确定在访问节点之前节点是否存在,或者您不想检查它,您也可以这样做:
MyJsonDoc.GetChildNodeValueInt32(' _id', 0{默认值,如果节点不存在});
MyJsonDoc.GetChildNodeValueText(['name', 'first'], ""{默认值,如果节点不存在});
MyJsonDoc.GetChildNodeValueDateTime('birth', Now{默认值,如果节点不存在});
用于创建文档节点:
MyJsonDoc.addchild('_id').int32 := 1;
with MyJsonDoc.addchild('name', ntObject) do begin
addchild('first').text := 'John';
addchild('last').text := 'Backus';
end;
MyJsonDoc.addchild('birth').dateTime := Now;
with MyJsonDoc.addchild('contribs', ntArray) do begin
addchild.text := ‘Fortran’;
addchild.text := ‘ALGOL’;
addchild.text := ‘Backus-Naur Form’;
addchild.text := ‘FP’;
end;
with MyJsonDoc.addchild(‘awards’, ntArray) do begin
with addchild(ntObject) do begin
addchild(‘award’).text := ‘National Medal of Science’;
addchild('year').int32 := 1975;
addchild('by').text := 'National Science Foundation';
end;
with addchild(ntObject) do begin
addchild('award').text := 'Turing Award';
addchild('year').int32 := 1977;
addchild('by').text := 'ACM';
end;
end;
MyJsonDoc.addchild('spouse');
MyJsonDoc.addchild('address', ntObject);
MyJsonDoc.addchild('phones', ntArray);
您也可以像这样创建/更新节点:
MyJsonDoc.SetChildNodeValueInt32('_id', 0);
MyJsonDoc.SetChildNodeValueText(['name', 'first'], 'John');
MyJsonDoc.SetChildNodeValueDateTime('birth', Now);
用于从 BSON 加载和保存:
MyJsonDoc.LoadFromFile(aBSONFileName, False{saxMode}, True{BSON});
MyJsonDoc.SaveToFile(aBSONFileName, False{saxMode}, True{BSON});
用于以 SAX 模式解析 JSON 文档:
MyJsonDoc.onParseText := procedure (Sender: TObject;
const Path: AnsiString;
const name: AnsiString;
const Args: array of const;
NodeSubType: TALJSONNodeSubType) -> NodeSubType: TALJSONNodeSubType)
begin
case NodeSubType of -> case NodeSubType of
nstFloat: Writeln(Path + ‘=’ + ALFloatToStr(Args[0].VExtended^, ALDefaultFormatSettings)); -> nstFloat: Writeln(Path + ‘=’ + ALFloatToStr(Args[0].VExtended^, ALDefaultFormatSettings));
nstText: Writeln(Path + ‘=’ + ansiString(Args[0].VAnsiString)); -> nstText: Writeln(Path + ‘=’ + ansiString(Args[0].VAnsiString));
nstObjectID: Writeln(Path + ‘=’ + ‘ObjectId(“‘+ALBinToHex(ansiString(Args[0].VAnsiString))+'”)’); -> nstObjectID: Writeln(Path + ‘=’ + ‘ObjectId(“‘+ALBinToHex(ansiString(Args[0].VAnsiString))+'”)’);
nstBoolean: Writeln(Path + ‘=’ + ALBoolToStr(Args[0].VBoolean,’true’,’false’)); -> nstBoolean: Writeln(Path + ‘=’ + ALBoolToStr(Args[0].VBoolean,’true’,’false’));
nstDateTime: Writeln(Path + ‘=’ + ALFormatDateTime(”’ISODate(“”yyyy”-”mm”-”dd”T”hh”:”nn”:”ss”.”zzz”Z”)”’, Args[0].VExtended^, ALDefaultFormatSettings)); -> nstDateTime: Writeln(Path + ‘=’ + ALFormatDateTime(”’ISODate(“”yyyy”-”mm”-”dd”T”hh”:”nn”:”ss”.”zzz”Z”)”’, Args[0].VExtended^, ALDefaultFormatSettings));
nstNull: Writeln(Path + ‘=’ + ‘null’);
nstRegEx: Writeln(Path + ‘=’ + ansiString(Args[0].VAnsiString));
nstBinary: Writeln(Path + ‘=’ + ‘BinData(‘+inttostr(Args[1].VInteger)+’, “‘+ansiString(ALBase64EncodeStringNoCRLF(ansiString(Args[0].VAnsiString)))+'”)’);
nstJavascript: Writeln(Path + ‘=’ + ansiString(Args[0].VAnsiString));
nstInt32: Writeln(Path + ‘=’ + ‘NumberInt(‘+inttostr(Args[0].VInteger)+’)’);
nstTimestamp: Writeln(Path + ‘=’ + ‘Timestamp(‘+inttostr(int64(cardinal(Args[0].VInteger)))+’, ‘+inttostr(int64(cardinal(Args[1].VInteger)))+’)’);
nstInt64: Writeln(Path + ‘=’ + ‘NumberLong(‘+inttostr(Args[0].VInt64^)+’)’);
end;
end;
MyJsonDoc.LoadFromJSON(AJsonStr, true{saxMode});
Delphi 的 ImageMagick 封装。
使用 ImageMagick® 创建、编辑、合成或转换位图图像。它可以读取和写入多种格式的图像(超过 200 种),包括 PNG、JPEG、GIF、HEIC、TIFF、DPX、EXR、WebP、Postscript、PDF 和 SVG。使用 ImageMagick 可以调整图像大小、翻转、镜像、旋转、扭曲、剪切和变换图像,调整图像颜色,应用各种特殊效果,或绘制文本、线条、多边形、椭圆和贝塞尔曲线。
示例:
var aWand: PMagickWand;
begin
//创建 ImageMagick 库
alCreateImageMagickLibrary({alcinoe_rootdir} + ‘\lib\dll\imagemagick\win32\imagemagick’, min(2, System.CPUCount){aThreadLimit});
try
//创建魔棒指针
aWand := ALImageMagickLib.NewMagickWand;
try
//加载图像
if ALImageMagickLib.MagickReadImage(aWand, pansiChar(aInputFilename)) <> MagickTrue then RaiseLastMagickWandError(aWand);
//设置压缩质量
如果 ALImageMagickLib.MagickSetImageCompressionQuality(aWand, 80) 不等于 MagickTrue,则调用 RaiseLastMagickWandError(aWand)。
//自动调整图像大小
如果 ALImageMagickLib.MagickAutoOrientImage(aWand) 不等于 MagickTrue,则调用 RaiseLastMagickWandError(aWand)。
//使用 Lanczos 滤波器调整图像大小
如果 ALImageMagickLib.MagickResizeImage(aWand, 640, 480, LanczosFilter) 不等于 MagickTrue,则调用 RaiseLastMagickWandError(aWand)。
//保存图像
ALImageMagickLib.MagickWriteImage(aWand, pansiChar(aOutputFilename))。
finally
ALImageMagickLib.DestroyMagickWand(aWand);
end;
finally
alFreeImageMagickLibrary;
end;
end;
MongoDB 客户端
Delphi 客户端,用于访问 MongoDB 数据库。一个 Delphi 驱动程序(带连接池),用于访问 MongoDB 服务器。连接池是一种缓存,用于维护数据库连接,以便在将来需要连接到数据库时可以重用这些连接。在连接池中,连接创建后会被放入池中,以便重复使用,而无需每次都建立新的连接。如果所有连接都在使用中,则会创建一个新的连接并将其添加到池中。连接池还可以减少用户建立数据库连接所需的时间。
示例:
aJSONDoc := TALJSONDocument.create;
aMongoDBClient := TAlMongoDBClient.create;
try
aMongoDBClient.Connect("", 0);
aMongoDBClient.SelectData('test.exemple',
'{fieldA:123}', // 查询条件
‘{fieldA:1, fieldB:1}’, // 返回字段选择器
aJSONDoc.node);
aMongoDBClient.disconnect;
for i := 0 to aJSONDoc.node.childnodes.count – 1 do
with aJSONDoc.node.childnodes[i] do
writeln(aJSONDoc.node.childnodes[i].nodename + ‘=’ + aJSONDoc.node.childnodes[i].text)
finally
aMongoDBClient.free;
aJSONDoc.free;
end;
示例,带有连接池:
aMongoDBConnectionPoolClient := TAlMongoDBConnectionPoolClient.create(aDBHost, aDBPort);
try
::Thread1::
aMongoDBConnectionPoolClient.SelectData('test.example',
'{fieldA:123}', // 查询条件
‘{fieldA:1, fieldB:1}’, // 返回字段选择器
aLocalVarJSONDOC.node);
::Thread2::
aMongoDBConnectionPoolClient.SelectData('test.example',
'{fieldA:999}', // 查询条件
‘{fieldA:1, fieldB:1}’, // 返回字段选择器
aLocalVarJSONDOC.node);
finally
aMongoDBClient.free;
end;
示例尾数据监控:
aMongoDBTailMonitoringThread := TAlMongoDBTailMonitoringThread.Create(
aDBHost,
aDBPort,
‘test.cappedCollectionExemple’
‘{}’, // 查询条件
‘{fieldA:1, fieldB:1}’, // 返回字段选择器
procedure (Sender: TObject; JSONRowData: TALJSONNode)
begin
writeln('New item added in cappedCollectionExemple: ' + JSONRowData.childnodes['fieldA'].text);
end,
procedure (Sender: TObject; Error: Exception)
begin
writeln(Error.message);
end);
….
aMongoDBTailMonitoringThread.free;
WebSocket 客户端
基于 WinHTTP 实现的 Delphi WebSocket 客户端。WebSocket 是一种通信协议,它允许在用户的浏览器和服务器之间建立双向交互通信会话。通过此协议,您可以向服务器发送消息,并在无需轮询服务器以获取回复的情况下接收基于事件的响应。
快速 TStringList
TALStringList 的工作方式与 Delphi 的 TStringList 相同,但它允许使用快速排序算法搜索名称=值,当列表已排序时。此外,TALStringList 使用一种与 Delphi TStringList 中使用的 AnsiCompareText 和 AnsiCompareStr 不同的、与本地无关的算法(基于每个字符的 8 位序数值)。因此,TALStringList 中的排序速度比 Delphi TStringList 快 10 倍。此外,TALStringList 不是一个 Unicode TStringList,而是一个 100% 的 Ansi 字符串列表。
TALNVStringList(NV 表示名称/值)与 TALStringList 相同(也使用快速排序算法),但这里的优化面向名称/值列表,而不是字符串列表。
TALHashedStringList:TALHashedStringList 与 TALStringList 相同,不同之处在于它使用内部哈希表,而不是快速排序算法。通过使用 TALHashedStringList 代替 TALStringList,可以在列表包含大量字符串时提高性能(否则,如果列表不包含大量字符串,则性能会低于 TALStringList,因为计算哈希的成本)。
PHP 运行时
ALPHPRunnerEngine 是一个简单但有用的组件,可用于在 Delphi 应用程序中轻松使用 PHP(任何版本)作为脚本语言。ALPHPRunnerEngine 允许在 Delphi 程序中执行 PHP 脚本,而无需 Web 服务器。ALPHPRunnerEngine 使用 PHP 的 CGI/FastCGI 接口 (php-cgi.exe) 与 PHP 引擎进行通信。
Memcached 客户端
Delphi 客户端,用于 memcached 数据库。
什么是 Memcached? 这是一个免费且开源的高性能分布式内存对象缓存系统,具有通用性,但主要用于通过减轻数据库负载来加速动态 Web 应用程序。
Memcached 是一个内存键值存储,用于存储来自数据库调用、API 调用或页面渲染的小块任意数据(字符串、对象)。
Memcached 简单但功能强大。 它的简单设计促进了快速部署、易于开发,并解决了大型数据缓存面临的许多问题。
GSM 组件
TAlGSMComm 组件实现了通过文本模式接口进行短信发送,该接口定义在 GSM 技术规范 07.05,版本 5.1.0,日期为 1996 年 12 月。 此规范有多种变体,广泛应用于诺基亚、西门子、爱立信等型号的手机。 我们内部测试了诺基亚 6230 型号,但诺基亚 7190、8890、6210 和 9110 型号也应该可以工作。 来自其他制造商的手机也可以工作,只要它们实现了文本模式接口。 大约 1/4 的当前手机可以连接到 PC(通过红外线或串行电缆),其中约 1/3 仅支持文本模式,1/3 仅支持 PDU 模式,而另一 1/3 同时支持文本和 PDU 模式。 一些手机(例如诺基亚 5190)支持短信,但它们使用专有协议,TALGSMComm 不支持该协议。
为了测试您的手机,请通过串口线或红外设备将手机连接到您的PC(请参阅您的手机文档,了解如何连接)。在终端窗口中输入“AT”以验证连接是否已建立(您应该从手机收到“OK”),然后输入“AT+CMGF=?”。响应应包含“1”,表示它支持文本模式。如果这两个测试都通过,则您的手机满足基本要求。
SQLite3 客户端
查询 SQLite3 数据库并以 XML 格式或 JSON/BSON 格式获取结果。
更多功能
CGI 运行器
HTTP 客户端 (WinInet/WinHTTP)
MySQL 客户端
NNTP 客户端
POP3 客户端
SMTP 客户端
XML 解析器
WIN64
不幸的是,在 win64 中,我们失去了所有 FastCode 的技术。 (这主要基于汇编)。 这意味着大多数函数的速度会慢 2 到 10 倍。 您可以尝试在 win64 和 Win32 上运行 /demo/ALStringBenchMark/,以查看速度差异。