尧图建网站 尧图建网站 YAOTU WEB BUILD 免费咨询
ARTICLE DETAIL

资讯详情

深耕网站建设与建站编程的一线实战洞察。

Delphi 12.3 源码编译安装 UniDAC 10.3.0 实战与排坑全记录

Delphi 12.3 源码编译安装 UniDAC 10.3.0 实战与排坑全记录 简介在Delphi开发中数据库访问组件一直是企业级应用的核心依赖。UniDAC作为一套可统一访问Oracle、SQL Server、MySQL、PostgreSQL、SQLite等主流数据库的通用组件凭借其灵活的Provider切换机制在ERP、MES、进销存等场景中广泛使用。然而面对Delphi 12.3这样的新版本许多开发者选择源码编译安装以获得版本匹配、可调试源码和路径可控等优势。本文将详细介绍从解压源码包、配置Library Path、编译运行时包与设计时包到处理IDE控件消失、数据库连接失败及64位平台适配等完整流程。通过实际案例帮助开发者一次性搞定UniDAC 10.3.0的部署与排坑。 Delphi 12.3 搭配 UniDAC 10.3.0这套组合在我手头的几个企业项目里已经跑了一年多。UniDAC 是 Devart 出品的通用数据库访问组件一套 API 能统一访问 Oracle、SQL Server、MySQL、PostgreSQL、SQLite、InterBase 这些主流数据库做 ERP、MES、进销存、PDA 采集的 Delphi 老开发基本都认识它。这篇文章不打算复述官方文档而是把我在 Delphi 12.3 下拿到 UniDAC 10.3.0 源码包之后从解压、编译、安装到项目实测的完整过程写出来连同编译过程中踩过的坑、IDE 里控件消失的排查思路一起讲透。适合正在被第三方组件折腾的 Delphi 开发者也适合第一次接触 UniDAC、想一次装明白的新手。1. 为什么放着双击安装版不用非要折腾源码版1.1 UniDAC 到底是什么为什么老项目里到处是它先花半分钟说清楚 UniDAC 的定位。传统上 Delphi 访问数据库要么用自带 TADOConnection、TFDConnectionFireDAC要么用第三方组件。UniDAC 的价值在于统一两个字你不用为每一种数据库各学一套连接方式TUniConnection、TUniQuery、TUniTable 这些组件在 ProviderName 里切换一下就能从 SQLite 换成 Oracle代码层面基本可以不动。我接手过不少老系统很多是 Delphi 7 时代留下的后来逐步升到 XE、10.4、12.3数据库从 Access 换到 SQL Server 再换到 PostgreSQL业务代码里跟数据库打交道最多的就是 UniDAC。它比 ADO 直接比 FireDAC 在驱动分发上省心尤其面对客户现场一堆五花八门的数据库环境时UniDAC 的驱动管理方式对我个人而言更顺手。1.2 源码版的三点不可替代价值安装版setup.exe双击装完控件直接出现在 IDE 里看起来很省事但我在 Delphi 12.3 上基本只用源码包。原因有三点。第一是版本匹配。Delphi 12.3 的 IDE 层和编译器层都比较新安装版很多时候内置的 BPL 是给旧版本编译的装上后要么控件不显示要么一编译就报 Cannot load package 之类的错。源码包需要自己在当前 IDE 里编译生成的一定是匹配当前版本的二进制从根上规避了版本错配。第二是能跟进去看内部实现。做企业项目时连不上数据库、事务不回滚、括号被转义这类疑难杂症光靠黑盒测试效率很低。源码版编译出的 DCU 配合 Delphi 的调试器可以 F7 一步走进 UniDAC 的源码看到它到底怎么发的 SQL、怎么处理的参数。这个能力在排线上事故时能救命。第三是路径可控。安装版会在系统里写注册表、往 Program Files 里塞文件重装系统后经常残留一堆垃圾。源码版把 BPL、DCP、DCU 全部输出到我自己指定的目录卸载时删目录就行清爽得多。1.3 再提一个前提授权要清爽说到源码包就绕不开授权问题。UniDAC 是商业组件正规使用需要购买源码授权或者对应版本的商业许可。我这里讲的技术流程适用于已经合法取得源码版授权的团队。如果只是评估试用也建议以官方渠道下载的评估包为准。道理很简单组件装得再顺授权有问题项目上线前照样要返工。2. 动手编译之前先把版本和路径这盘棋摆明白2.1 版本对应关系Delphi 12.3 的编译器版本号进入编译之前有一个东西必须弄清楚——Delphi 的 IDE 版本号和编译器版本号不是一回事。你打开 Help About看到的 RAD Studio 12.3 是产品名而编译期识别用的是另一个版本号。UniDAC 源码包里Source 目录下会按编译器版本分子目录文件名通常形如 Delphi26、Delphi27、Delphi29 之类。Delphi 10.3 Rio 对应 Delphi2610.4 Sydney 对应 Delphi2711.x 对应 Delphi2812.x 对应 Delphi29。所以 UniDAC 10.3.0 的源码里支持 Delphi 12.3 的那个目录一般就是 Delphi29 或者带 29 的文件夹名。先确认这个对应关系后面找工程文件才不会懵。如果目录名和实际版本对不上还有一个笨办法随便打开源码目录里的任意一个 .dproj 文件看它的中 S 语言版本字段或者直接搜 Delphi29 字样基本上能定位到正确的入口。2.2 目录结构解压后先认路把 rar 解压出来之后不要急着点编译。正规源码包一般包含这些内容目录/文件作用Source核心源码按编译器版本分子目录Demo官方示例工程学习和验证用Docs文档包含 Provider 配置说明Units部分版本的公共同单元Setup某些版本会附带安装脚本我习惯把源码放在一个固定位置比如 D:\DelphiLib\UniDAC-10.3.0而不是解压到桌面或者下载目录。因为后面配置 Library Path、BPL 输出路径都要引用这个路径一旦解压位置变来变去IDE 里的路径就会乱套。另外两个小原则路径不要带中文最好是纯英文不要在路径里留空格的目录名。Delphi 的路径系统对空格和中文处理得不算差但第三方组件编译时偶尔会抽风没必要给自己埋雷。2.3 清理旧组件残留如果机器上曾经装过其他版本的 UniDAC强烈建议先清理干净再装 10.3.0。常见的残留有几个位置IDE 的 Component Install Packages 列表里还挂着旧版设计时包BPL 文件散落在 C:\Windows\System32 或旧安装目录Library Path 里还指着旧版的 DCU 目录。不清干净的后果很典型编译新包时提示 BPL 冲突打开窗体时提示找不到某个类或者工具栏上同时出现两个版本的组件代码里用的类名却被 IDE 解析到旧版本。我的清理步骤很简单先在 Install Packages 里卸载旧包再搜索并删除所有 UniDAC 相关的 BPL、DCP、DCU 文件最后打开 Tools Options Library把和旧版本相关的路径逐条删掉。不要嫌麻烦这一步省了后面会加倍还回来。2.4 Library Path 的事先规划Library Path 是 Delphi 找 DCU 和 DCP 的索引。我见过很多装完组件后编译报 Unit not found: Uni 的人十有八九是 Library Path 没配好。在动手编译前先规划好三个输出目录DCU 输出目录比如 D:\DelphiLib\UniDAC-10.3.0\Dcu\Win32BPL 输出目录比如 D:\DelphiLib\UniDAC-10.3.0\BplDCP 输出目录可以和 BPL 放一起。这几个目录在编译包的工程选项里会用到。之所以先规划是因为后面编译设计时包时IDE 需要同时知道运行时包在哪儿、类库在哪儿提前定好可以减少来回折腾。3. 从解压到 IDE 组件面板出现 UniDAC 页签的完整过程3.1 先编译运行时包UniDAC 的包工程分两类运行时包Runtime Package文件名一般不带 dcl 前缀和设计时包Design-Time Package文件名以 dcl 开头。正确顺序是先编译运行时包再编译设计时包。操作步骤如下打开 Delphi 12.3 IDEFile Open Project定位到源码目录下对应 Delphi29 的子目录。找到运行时包工程文件通常扩展名是 .dpk 或 .dproj文件名形如 UniDAC290.dproj具体后缀数字以你手上版本为准。在 Project Manager 中右键该项目选择 Build。等待编译输出确认无错误后在 Project Options 里检查 Output directory 和 DCP output directory 是否指向规划好的目录。编译过程中如果提示找不到某些 DCU检查 Library Path 是否已包含源码目录下的核心子目录比如 Source 下的 DAC 和 Uni 目录。3.2 编译设计时包并安装到 IDE运行时包编译通过后同一个目录下找 dcl 开头的设计时包工程比如 dclUniDAC290.dproj。这个包才负责把组件图标画到 IDE 组件面板上。同样的操作打开工程、Build、确认无错误。编译完成后接着执行 Component Install Packages点击 Add 按钮选择刚才生成的 dclUniDAC 开头的 BPL 文件。安装成功后组件面板上会多出一个 UniDAC 页签里面出现 TUniConnection、TUniQuery、TUniTable、TUniTransaction、TUniScript 等组件。到这里视觉效果上已经装好了。3.3 配置 DCU 输出目录与搜索路径组件面板出现只是第一步。为了让你的新工程能直接编译必须在 Tools Options Language Delphi Library 里把以下路径加到 Library Path源码目录下的 Source 核心路径源码目录下对应 Delphi29 的路径编译时生成的 DCU 目录如果它不在源码目录里。另外注意左侧 Platform 框里要选对平台。默认是 Win32但如果你的工程面向 Win64需要把 Platform 切换到 Win64重新检查一遍 Library Path很多组件源码包里 Win32 和 Win64 的 DCU 目录是分开的。漏配 64 位路径是特别常见的坑后面 4.3 节单独讲。3.4 遇到编译报错怎么办我自己在新装一套环境时也踩过几次编译报错这里把最常见的几个列出来报错现象原因处理方式Cannot find unit DAC缺少核心 DCU 路径检查 Library Path 是否包含 Source 核心目录Package ... conflicts with ...存在旧版本 BPL卸载并删除旧版包文件E2201 Procedure or function name expected编译器版本不匹配确认打开的是 Delphi29 对应的工程文件Error reading PackageBPL 依赖的其他包缺失先编译并安装依赖的运行时包如果编译时提示缺少某个第三方依赖包比如 FastMM 或者特定版本的 JSON 库先记下依赖包的名字去源码包的 Dependency 说明里找。UniDAC 10.3.0 整体上依赖不多正常情况不会出现连环缺库的问题但 Windows 环境下偶尔会有杀毒软件锁定 BPL 导致编译失败临时关掉防护再试一次就能判断。4. 别急着高兴数据库连不上才暴露真问题4.1 用 SQLite 项目快速验证组件面板出现 UniDAC 页签只能说明显示成功真正验证安装是否可用的方式是跑一个能连上库的最小项目。SQLite 是最适合做验证的数据库因为它是文件型数据库不需要安装服务端一个 .db 文件就能完成全流程。新建一个 VCL Application在窗体上放一个 TUniConnection、一个 TUniQuery、一个 TButton、一个 TMemo。按钮里写以下代码procedure TForm1.Button1Click(Sender: TObject); begin UniConnection1.ProviderName : SQLite; UniConnection1.Database : D:\temp\unidac_test.db; UniConnection1.LoginPrompt : False; UniConnection1.Connect; UniQuery1.Connection : UniConnection1; UniQuery1.SQL.Text : SELECT name, age FROM users ORDER BY id; UniQuery1.Open; while not UniQuery1.Eof do begin Memo1.Lines.Add( UniQuery1.FieldByName(name).AsString - UniQuery1.FieldByName(age).AsString ); UniQuery1.Next; end; end;运行后如果 Memo 里能输出数据说明 UniDAC 的运行时包、设计时包、库路径、Provider 都正常。没有 users 表的话先用 SQLite 工具建一张带数据的表或者直接用 TUniScript 执行建表和插入脚本。4.2 常见连接失败原因对照表这个最小验证项目往往比安装过程更能暴露问题。我见过比较多的连接失败场景有下面几种现象原因对策Unsupported provider 或 Provider not foundProviderName 拼写错误或驱动缺失确认 ProviderName 为 SQLite、MySQL 等标准名称Unable to load librarySQLite 动态库路径不对把 sqlite3.dll 放到 exe 同目录或配置 DLL 搜索路径Login failed / Access denied账号密码错误或连接串参数不对核对用户名、密码、服务器端口Cannot open database数据库文件路径不可写检查文件路径权限Driver not found64 位平台下缺 64 位驱动配置 64 位 Library Path 和 DLL排查连接问题有一个基本顺序先确认 ProviderName 无误再确认动态库文件存在然后用 TUniConnection 和 DBMonitorUniDAC 自带日志工具看底层发出的连接请求最后再怀疑代码逻辑。4.3 64 位目标平台的一个隐藏坑如果只是为了做桌面工具32 位够用但现在的项目打包基本都是 Win64。切换到 64 位目标平台后你可能会遇到一个神奇的报错同一份代码Win32 编译运行正常Win64 一连接就提示找不到驱动或找不到库文件。原因多半是 UniDAC 源码包里 Win32 和 Win64 的 DCU 是分开目录编译的而你只把 Win32 的路径加到了 Library Path。还有一种情况是 sqlite3.dll 是 32 位版本Win64 进程加载不了 32 位 DLL。解决办法很明确在 Tools Options Library 里把 Platform 切到 64-bit Windows分别添加对应 64 位版本的 DCU 路径同时保证所有第三方 DLL 也是 64 位。另外Delphi 12.3 下编译出来的包要确保 BPL 也是匹配平台的设计时包默认是 32 位用于 IDE但运行时包的 DCU 要覆盖两个平台。5. 组件落地之后我在项目里最常用的几个 UniDAC 姿势5.1 参数化 select 查询老生常谈但真有用UniDAC 的 TUniQuery 参数化查询是平时用得最多的功能。好处有两个一是避免 SQL 注入二是不用手工拼字符串减少单引号转义带来的低级错误。UniQuery1.SQL.Text : SELECT * FROM orders WHERE customer_id :id AND status :st; UniQuery1.ParamByName(id).AsInteger : 1001; UniQuery1.ParamByName(st).AsString : Pending; UniQuery1.Open;注意两点参数名前面的冒号是 UniDAC 的标准写法千万不要用问号通配AsInteger、AsString 这些赋值会做类型转换比直接传字符串可靠。如果查询条件里有 IN 列表UniDAC 的新版本支持数组参数但老项目里我习惯用临时表或者循环拼多个参数。5.2 FireMonkey PDA 扫码结果的入库查询移动端 PDA 扫码场景在仓库和现场作业里很常见。扫码枪或 PDA 扫描头扫到的条码最终要拿到后端数据库里查对应物料或工单信息。用 FireMonkey 写 Android 端程序时UniDAC 同样可以接入 SQLite 或直接连服务器数据库。我通常的做法是扫描头把结果送到一个 TEdit 控件按回车触发查询。示例代码如下procedure TForm1.edtScannerKeyDown(Sender: TObject; var Key: Word; var KeyChar: Char; Shift: TShiftState); begin if Key 13 then begin UniQuery1.SQL.Text : SELECT product_name, stock FROM products WHERE barcode :bc; UniQuery1.ParamByName(bc).AsString : edtScanner.Text; UniQuery1.Open; if not UniQuery1.IsEmpty then lblResult.Text : UniQuery1.FieldByName(product_name).AsString else lblResult.Text : 未找到; edtScanner.Clear; end; end;这个模式很朴素但稳定。要注意的是 PDA 上数据库连接方式如果走局域网直连服务器需要考虑网络中断、连接超时、断线重连如果先本地缓存再同步SQLite 文件路径和读写并发就是重点。UniDAC 对 SQLite 的支持够用配合 TUniTransaction 管理事务能在弱网环境下做出可靠的数据落地。5.3 TUniQuery 直接生成 JSON现在很多系统要向前端提供 JSON 接口用 Delphi 做服务端时把 TUniQuery 查询结果转成 JSON 是高频需求。Delphi 自带的 System.JSON 配合 UniDAC 就能完成不需要额外引第三方库。uses System.JSON; function QueryToJson(AQuery: TUniQuery): string; var Arr: TJSONArray; Obj: TJSONObject; I: Integer; begin Arr : TJSONArray.Create; try AQuery.First; while not AQuery.Eof do begin Obj : TJSONObject.Create; for I : 0 to AQuery.FieldCount - 1 do Obj.AddPair(AQuery.Fields[I].FieldName, AQuery.Fields[I].AsString); Arr.AddElement(Obj); AQuery.Next; end; Result : Arr.ToJSON; finally Arr.Free; end; end;这个函数简单实用字段名直接取自数据库列名。字段值统一转字符串虽然丢掉了类型信息但作为通用接口已经够用。真遇到需要保持数字类型的前端可以再按字段类型分别用 TJSONNumber 和 TJSONString 处理。5.4 周边工具MD5、执行 cmd 命令、Memo 入 Excel数据库之外项目里经常要拼一些周边能力。这里列几个我常用的代码片段。字符串 MD5 计算Delphi 10.4 之后用 System.Hash 很方便uses System.Hash; function GetMd5(const S: string): string; begin Result : THashMD5.GetHashString(S); end;登录密码校验、文件完整性比对都能用。Delphi 自带这一套不用再找外部加密库。执行 DOS 命令并获取返回值我常用 CreateProcess 加重定向管道实现uses Winapi.Windows, System.SysUtils; function ExecCmdAndGetOutput(const CmdLine: string): string; var SA: TSecurityAttributes; SI: TStartupInfo; PI: TProcessInformation; hOutRead, hOutWrite: THandle; Buffer: array[0..1023] of AnsiChar; BytesRead: Cardinal; Output: string; begin Result : ; SA.nLength : SizeOf(SA); SA.bInheritHandle : True; SA.lpSecurityDescriptor : nil; CreatePipe(hOutRead, hOutWrite, SA, 0); SetHandleInformation(hOutRead, HANDLE_FLAG_INHERIT, 0); FillChar(SI, SizeOf(SI), 0); SI.cb : SizeOf(SI); SI.hStdOutput : hOutWrite; SI.hStdError : hOutWrite; SI.dwFlags : STARTF_USESTDHANDLES or STARTF_USESHOWWINDOW; SI.wShowWindow : SW_HIDE; if CreateProcess(nil, PChar(cmd.exe /c CmdLine), nil, nil, True, CREATE_NO_WINDOW, nil, nil, SI, PI) then begin CloseHandle(hOutWrite); Output : ; while ReadFile(hOutRead, Buffer, SizeOf(Buffer), BytesRead, nil) and (BytesRead 0) do Output : Output string(Buffer); WaitForSingleObject(PI.hProcess, INFINITE); CloseHandle(hOutRead); CloseHandle(PI.hThread); CloseHandle(PI.hProcess); Result : Trim(Output); end; end;这段代码在 Windows 下跑 cmd 命令并捕获输出比如调用外部工具、查系统信息都很实用。调用时程序界面不会弹出黑框。至于把 Memo 里的数据导入 Excel我多半不走 UniDAC直接用 CreateOleObject(Excel.Application) 或者 TADOConnection 的 Microsoft.Jet.OLEDB 连接 Excel 文件。UniDAC 的 ODBC Provider 确实能接 Excel但做这种单次导入导出没必要增加额外依赖。ADO 连接 Excel 的做法很多用连接串 ProviderMicrosoft.Jet.OLEDB.4.0;Data Sourcexxx.xlsx;Extended PropertiesExcel 12.0 即可。6. 那些年我们一起踩过的控件丢之坑6.1 现象描述控件为什么总是消失很多 Delphi 开发都遇到过这种诡异现象UniDAC 组件装好了IDE 里放着也正常但关掉 IDE 再打开组件面板上的 UniDAC 页签不见了或者已打开窗体上的 UniDAC 组件显示成控件不存在需要重新放置。有的项目还会出现每次进入 IDE 都丢失控件重新放置后保存再打开还是丢。这个问题的本质不是控件没装好而是 IDE 在启动时没有成功加载对应的设计时包。6.2 排查链路从 Install Packages 到文件权限遇到控件丢失按下面的链路排查基本能定位打开 Component Install Packages看列表里 Devart UniDAC 项是否还在。如果显示灰色或提示找不到文件说明 BPL 文件路径失效或者文件被移动、删除。检查 BPL 文件是否存在。如果存在确认它的版本是否和当前 IDE 匹配。常见情况是一个 BPL 同时被多个版本的 Delphi 使用或者路径被改过。检查 IDE 启动时有没有什么安全软件拦截了 BPL 加载。Delphi 的 BPL 本质是 DLL杀毒软件和系统防篡改策略有时会拦截加载导致 IDE 启动时静默失败。查看 Windows 事件查看器里的应用程序日志是否有加载 BPL 失败的记录。确认当前登录用户对 BPL 所在目录有完全控制权限。如果 BPL 放在 Program Files 下而 IDE 以普通用户运行加载就会失败。我遇到最多的是路径失效和权限问题源码包目录从 D 盘换到 E 盘旧的 BPL 路径残留在注册表里IDE 启动时按旧路径加载失败就表现为控件丢失。6.3 根治思路目录规划 版本隔离解决之后要防复发我的做法有三个固定原则。第一BPL 和 DCP 统一输出到一个固定目录比如 D:\DelphiLib\Bpl这个目录放在普通用户可写的地方不要放 Program Files。配置好之后不要随意移动。第二每个 Delphi 版本一个目录避免不同版本的 BPL 混在一起。比如 D:\DelphiLib\Bpl\D12 是给 Delphi 12 用的D11 是给 Delphi 11 用的。不要省这一点空间版本混合是控件丢失和编译错乱的最大来源。第三安装包的路径写入 Library Path 后定期做一次检查。升级 Delphi 或迁移电脑后重新走一遍第 3 节的编译流程不要直接把旧目录拷过来。如果已经出现控件丢失重新打开 Install Packages移除失效率比较高的旧包再重新 Add 一次正确的 BPL 文件保存并重启 IDE。绝大多数情况下只要 BPL 路径稳定这个问题就不会再犯。最后再说个经验。很多刚接触源码版 UniDAC 的同事会问为什么官方不干脆出一个适配所有 Delphi 版本的安装包答案是做不到也没必要。Delphi 每一次版本升级编译器和 RTL 都会变第三方组件必须跟着重新编译。理解了这一点就会明白为什么从源码编译安装才是 Delphi 环境下最省心的组件管理方式。而 UniDAC 作为一套成熟的数据库访问组件在 Delphi 12.3 上把源码路径、库路径、BPL 输出这三个点管好后面几乎不会再为连接问题发愁。本文还有配套的精品资源点击获取
返回列表