Lazarus debug的坑

从其它平台迁移而来 最近在研究Lazarus写dll,已经踩了不少坑了,这下又踩了个不大不小的坑,记录下。 问题 在dll工程里,断点失效,根本没办法调试 解决方案 网上查了N多资料,个中辛酸在此不表,终于找到些蛛丝马迹。 Lazarus在windows上默认使用的是FpDebug内置的Dwarf,这货本身就不支持在dll中调试,法了个克!切换为gdb,立马OK! 不过,据说gdb在windows上有bug,这……反正FpDebug的bug遇到了也不是一个两个了,先用着再说。

2022-11-20 23:44:48 · 1 分钟 · 慢步道人

Lazarus编写dll与接口注意事项小结

从其它平台迁移而来 之前用lazarus编写了使用IInterface的dll,可惜没有成功。当把IInterface编译到exe里时,功能正常,编译到dll里再在exe里调用就不正常,原因未深究,不过大致也知道是哪一类问题,至于还有没有其它问题,暂未可知。 闲来有空,有写了点Demo来,有了不少新发现,在此记录下: 只有使用exports导出的函数才能在dll外部调用 只有使用stdcall修饰的函数传参规则才与标准C的传参规则相同,其它遵守标准C传参规则的语言可以正常调用;否则,只有lazarus编写的程序可以正常调用 入参为string类型时,无论是否使用stdcall修饰,lazarus编写的程序调用正常,其它语言未测试 返回值或出参为string类型时,调用报External: ACCESS VIOLATION错误;但参数为PChar时,调用正常 入参/出参/返回值为结构体时,调用正常 string类型传参是指针/引用拷贝,结构体传参是值拷贝 string做入参时,由主调函数分配内存并增加引用计数,被调函数执行时再次增加引用计数,被调函数结束时减少引用计数,此时引用计数不为0不释放内存,主调函数结束时再次减少引用计数,引用计数为0释放内存,该内存由exe分配,因此释放不报错;做出参时,由被调函数执行时分配内存并增加引用计数,被调函数返回时先赋值给主调函数的变量,增加引用计数,再结束被调函数,减少引用计数,主调函数结束时再次减少引用计数,此时引用计数为0释放内存,但该内存是由dll分配,因此产生External: ACCESS VIOLATION错误 string类型不适合在dll和exe之间传参(尤其是出参) 返回值为对象时,调用异常;入参/出参为exe创建的对象时,调用正常 结论 根据测试得出的结论,可能不严谨: 指针做为形参(入参/出参)传递没有问题,但必须遵守谁创建谁释放的原则;指针做为返回值可能会有隐患 对象传参实际传的是对象的指针,规则与指针相同 返回值适合传递值拷贝的类型,如整型、浮点型、布尔型、结构体、指针(但指针指向的内存要遵守谁创建谁释放的原则,不过一般不直接使用)等 字符串、结构体的生命周期是由编译器维护的,使用需慎重

2022-09-13 20:40:27 · 1 分钟 · 慢步道人

*.frf报表中字段计算的坑

从其它平台迁移而来 老坑 *.frf是FastReport 2.x的报表模板,现维护的老项目中有使用到该报表。 问题描述 报表通过数据集DS和报表变量V1、V2、V3等获取数据,并在模板中进行展示。 单独展示数据集中的某个字段:[DS."D1"] 展示数据集中的某两个字段的运算结果:[[DS."D1"]+[DS."D2"]] 单独展示某个变量:[V1] 展示数据集中的某个字段与变量的运算结果:[[DS."D1"]+[V2]] 以上都是没有问题的,但当需要展示两个变量的运算结果时就不行了,[V1]+[V2]实际展示的是两个变量的字符串连接,因为报表变量本来就是字符串。查看模板其它写法,发现有使用尖括号<>的,尝试后也不行,[V1]+<V2>实际展示的只有V2的值。 由于报表变量本身就是字符串,想着通过数据类型转换来解决,但非常遗憾,报表没有提供把字符串转为数值的函数。 实在不行就只能考虑在代码中计算完之后再赋值给报表变量了,但这样就牺牲了报表的灵活性了,乃是没有办法的最后的办法了。 最后灵光一现,既然数据集字段与变量可以运算,那加个0是不是也可以运算?一试果然可行! 结果 展示某两个变量的运算结果:[0+[V1]+[V2]-[V3]] 问题解决了,不过总感觉是个偏方,不晓得正统的解决方案是什么。 不过话说回来,FastReport 2.x已经很古老了,除了老项目维护基本不可能会用到,因为现在连FastReport 3+用得都很少了,毕竟现在已经是什么乱七八糟的牛鬼蛇神都有的元宇宙时代了,能解决问题就好。

2022-08-31 23:40:11 · 1 分钟 · 慢步道人

Lazarus压缩/解压zip乱码问题

从其它平台迁移而来 Lazarus压缩/解压zip文件可以使用Zipper单元中的TZipper/TUnZipper类来实现,但是在有中文文件名时需要注意,否则会出现乱码。 压缩 TZipper的Zip类方法无需创建实例即可直接生成zip压缩文件。 TZipper实例的ZipFile方法是压缩一个指定的文件生成zip压缩文件,ZipFiles方法是压缩多个指定的文件生成zip压缩文件,UnZipAllFiles方法是配合Entries等属性生成zip压缩文件。 解压 TUnZipper的UnZip类方法无需创建实例即可直接解压zip文件。 TUnZipper实例的UnZipFile方法是解压出一个指定的文件,UnZipFiles方法是解压出多个指定的文件,UnZipAllFiles方法可以从zip文件中解压出所有文件。 乱码 无中文文件名的情况下,以上类方法和实例方法使用都是正常的,与其它压缩/解压工具交叉使用也不会出现问题。 当存在中文文件名时,成对使用以上压缩/解压方法,从结果上来说是没什么问题的,但与其它压缩/解压工具交叉使用时就会出现文件名乱码问题。 乱码其实还是字符编码的问题,Lazarus默认使用UTF8编码,windows默认使用OEM对应的编码,对于中文windows就是GBK编码,于是就出问题了。 解决方案 TZipper有UseLanguageEncoding属性,TUnZipper有UseUTF8属性,均设置为True,再进行压缩/解压即可,因此,类方法是肯定不行的了。 不过,这两个属性在语意上却十分让人费解,因为属性为False时,zip文件头里的文件名实际使用的是UTF8编码,而当属性为True时,zip文件头里的文件名实际使用的却是GBK编码,搞不懂这些老外的想法。 对了,好像要使用FPC 3.2.0+的编译器版本才可以。

2022-08-24 22:10:38 · 1 分钟 · 慢步道人

idhttp POST的坑

从其它平台迁移而来 坑 最近要和一个平台提供的http接口进行对接,由于服务不是部署在公网上的,所以没办法直接在开发环境下直接调试,又不能在客户的测试机上部署开发环境,只能选择加日志这种古老的方法。 在对接过程中却出现了莫名其妙的问题:POST的内容是一样的,但返回的内容却不一样,更准确点说是有的接口返回正常有的返回不正常(其实还是测试有限,测试多的话还会出现同一接口有的请求正常有的不正常)。 平台提供的word接口文档写得真的是……一言难尽,由此也对接口的准确性、可靠性等保持怀疑。不过,这次用我们提供的数据,平台方给出了相应的中间结果(中间结果一致)及返回结果,还有postman和curl的测试截图,充分证明接口以及数据请求是没有问题的。 在客户测试机上装了curl测试也证明接口没问题。(问为什么一开始没想到用curl?因为windows默认没有,而且utf8还会显示乱码,习惯性的就没想起来用) 请求头也改了,没用一样的效果。 最后实在找不出问题,就只能进行TCP抓包了,这一抓还就真抓出问题了: 原始数据 1 /knwRBV5D4Qtk7RzoQhtBUSMXQig3zURYmeSQBB17NVr6qddCkTxS7e0oO/qfNCkuX14vGsxEoLLN4KS5vtQWDs5on+GeAE5LadCZuHDCe7M25GitNKqnsCfC5qVmti1LyxLxYg2JpLP6GylWERWBOmbP2yO2Aiuey6V526rlRICnidM1W0A4ziNMSjGCng0n5Md4so/RjswNdcE4C5F0kBEGRWH0ZK+QdkZMs4zL84Pu/aiSMpiID9Mm+jtdLZuk0m0UtEd1MmxnU2KPdQz9057JAtM5LIj4YenZl3J86OPWtb9DE6a+410CWBawZY1vItZ+43Kh/QPnkw6Qe4toXRnF84X/ijtiWkTt4moJT87xDpf/TXEd7LRkddWPRRGF3KHnUKacLySwMmXkU6CQMazE1Kh1ZGML6zl1weaq4xVulFwhGfp2XKzYdZfT3uq4yqVr30AaEqYoy2/P1MkhTs5on+GeAE54r939gdklpefguipLJVBpWk/B5S9QsCDxDbfGYNxJo3rIAxDL7sjjlmVL1RjU86sHsNIbmRii7dL70pf5qcIMJzryGmtn94SAE2HjLw0abfr0A9amRsdIzs5on+GeAE5RIxdCKDfNRFnPqLzNU5stMSDcpuafJpNhUXDbQOMlPungXJHHZAgbE2XtoI4geIRYjiyBLDMQuB0l5WvfDhpRnYo1VaEu7J0tRuezwUplK61p4I8giLwAtO+yNMRV+J65g9XaT8vmf8gxmtK3wEFrve7HwsYH0QhlQQiMilY/JVsiHZS6+ID/w== 发送后抓到的却是 1 /knwRBV5D4Qtk7RzoQhtBUSMXQig3zURYmeSQBB17NVr6qddCkTxS7e0oO/qfNCkuX14vGsxEoLLN4KS5vtQWDs5on+GeAE5LadCZuHDCe7M25GitNKqnsCfC5qVmti1LyxLxYg2JpLP6GylWERWBOmbP2yO2Aiuey6V526rlRICnidM1W0A4ziNMSjGCng0n5Md4so/RjswNdcE4C5F0kBEGRWH0ZK+QdkZMs4zL84Pu/aiSMpiID9Mm+jtdLZuk0m0UtEd1MmxnU2KPdQz9057JAtM5LIj4YenZl3J86OPWtb9DE6a+410CWBawZY1vItZ+43Kh/QPnkw6Qe4toXRnF84X/ijtiWkTt4moJT87xDpf/TXEd7LRkddWPRRGF3KHnUKacLySwMmXkU6CQMazE1Kh1ZGML6zl1weaq4xVulFwhGfp2XKzYdZfT3uq4yqVr30AaEqYoy2/P1MkhTs5on+GeAE54r939gdklpefguipLJVBpWk/B5S9QsCDxDbfGYNxJo3rIAxDL7sjjlmVL1RjU86sHsNIbmRii7dL70pf5qcIMJzryGmtn94SAE2HjLw0abfr0A9amRsdIzs5on+GeAE5RIxdCKDfNRFnPqLzNU5stMSDcpuafJpNhUXDbQOMlPungXJHHZAgbE2XtoI4geIRYjiyBLDMQuB0l5WvfDhpRnYo1VaEu7J0tRuezwUplK61p4I8giLwAtO+yNMRV+J65g9XaT8vmf8gxmtK3wEFrve7HwsYH0QhlQQiMilY/JVsiHZS6+ID/w=%3D 最后的=被转码为%3D了! 解决 找到原因就好办了 1 2 //idhttp.HTTPOptions := [hoForceEncodeParams]; //默认强制对参数进行转码 idhttp.HTTPOptions := []; //去掉就OK了

2022-07-12 21:47:37 · 1 分钟 · 慢步道人

Lazarus构造/析构等方法的执行顺序

从其它平台迁移而来 AfterConstruction、BeforeDestruction是TObject本身就有的方法,Loaded是从TComponent才有的方法,好好利用的话就可以更精准的控制对象的生命周期或者初始化/清理工作。虽然知道这点,而且也经常在自己的程序中使用,但还是会经常搞错执行顺序,因此专门记录一下以备忘备查。 Form graph TD f1[inherited Create 前] --> f2[inherited Loaded 前] --> f3[inherited Loaded 后] --> f4[inherited Create 后] --> f5[inherited AfterConstruction 前] --> f6[FormCreate] --> f7[inherited AfterConstruction 后] --> f8[FormResize] --> f9[FormShow] --> f10[FormCloseQuery] --> f11[FormClose] --> f12[inherited BeforeDestruction 前] --> f13[FormHide] --> f14[FormDestroy] --> f15[inherited BeforeDestruction 后] --> f16[inherited Destroy 前] --> f17[inherited Destroy 后] DataModule graph TD d1[inherited Create 前] --> d2[inherited Loaded 前] --> d3[inherited Loaded 后] --> d4[inherited Create 后] --> d5[inherited AfterConstruction 前] --> d6[DataModuleCreate] --> d7[inherited AfterConstruction 后] --> d8[inherited BeforeDestruction 前] --> d9[DataModuleDestroy] --> d10[inherited BeforeDestruction 后] --> d11[inherited Destroy 前] --> d12[inherited Destroy 后] Frame graph TD f1[inherited Create 前] --> f2[inherited Loaded 前] --> f3[inherited Loaded 后] --> f4[inherited Create 后] --> f5[inherited AfterConstruction 前] --> f6[inherited AfterConstruction 后] --> f7[FrameResize] --> f8[inherited BeforeDestruction 前] --> f9[inherited BeforeDestruction 后] --> f10[inherited Destroy 前] --> f11[inherited Destroy 后] 总结 Loaded是在Create的过程执行的,应该是用来做一些加载资源之类或其它辅助构造的工作...

2022-06-24 22:53:40 · 1 分钟 · 慢步道人

Lazarus速查

从其它平台迁移而来 Package->Install/Uninstall Packages AnchorDockingDsgn:安装后转为一体式IDE LazActiveX:安装后可安装ActiveX组件 lazdaemon:可开发windows服务 lazprojectgroups:使IDE支持工程组 lazvlc:VLC 播放器组件,需要V2版本以上的libvlccore.dll和libvlc.dll Package->Online Package Manager DBTreeViewAndDBCntrlGrid:可从数据集中把树型数据直接显示为树 DCPcrypt:常用加密/解密,如DES、3DES、AES、RC2、RC4、RC5、RC6、MD4、MD5、SHA1、SHA256、SHA384、SHA512等 自带单元 fpjson、jsonscanner、jsonparser:自带JSON jsonConf:JSON配置 fphttpclient:HTTP客户端 fphttpserver:HTTP服务端 base64:BASE64编码/解码 md5:MD2、MD4、MD5算法 sha1:SHA-1(RFC 3174)算法 crcCRC32、CRC64和CRC128算法 开源库 dataset-serialize:数据集与JSON序列化/反序列化 CEF4Delphi:谷歌浏览器内核,依赖DCPcrypt

2022-06-23 22:55:57 · 1 分钟 · 慢步道人

Lazarus报Error: Undefined symbol

从其它平台迁移而来 在使用Lazarus编写动态库的过程中遇到了报Error: Undefined symbol:错误的问题,死活编译不过去,加了LCL包依赖也不行,找了N久终于在一个英文网站上找到了解决办法。 Error: Undefined symbol:错误会依据所写的代码用到的单元不同而有一定的差异,我遇到的报错大致如下: 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 project1.lpr(18,1) Error: Undefined symbol: WSRegisterCustomImageListResolution project1.lpr(18,1) Error: Undefined symbol: WSRegisterMenuItem project1.lpr(18,1) Error: Undefined symbol: WSRegisterMenu project1.lpr(18,1) Error: Undefined symbol: WSRegisterMainMenu project1.lpr(18,1) Error: Undefined symbol: WSRegisterPopupMenu project1.lpr(18,1) Error: Undefined symbol: WSRegisterDragImageListResolution project1.lpr(18,1) Error: Undefined symbol: WSRegisterLazAccessibleObject project1.lpr(18,1) Error: Undefined symbol: WSRegisterControl project1.lpr(18,1) Error: Undefined symbol: WSRegisterWinControl project1.lpr(18,1) Error: Undefined symbol: WSRegisterGraphicControl project1....

2022-06-06 21:59:18 · 1 分钟 · 慢步道人

慎用 out

从其它平台迁移而来 最近需要评估一下海康摄像头不同抓拍方式的性能,以及封装类的可靠性。 在测试过程中,又发现了当初遇见的设备内存抓拍报错的问题。当初排查的结论是:当封装类开启预览的情况下,使用设备抓图有较高概率抓拍失败。由于预览是必需的,最终选择了预览抓拍。 现在,换用lazarus进行测试,发现设备抓图必失败,与是否预览无关。一点点调试,发现直接调用SDK原始方法进行设备抓图正常,使用封装类的设备抓图就不行,那肯定是封装类出了问题。 最终发现,封装类的设备抓图使用了out来修饰参数,参数是TMemoryStream和TJPEGImage对象,尝试去掉out修饰符,然后就一切正常了。 记得很久前专门研究过out和var修饰符的区别,当时查阅的结果是:out和var修饰的参数都是传址的,区别是out会对参数进行初始化,而var则不会。 另外,参数为对象的情况,实际也是传址的。 本次发现的问题可能就是使用out来修饰对象参数导致的,但并没有进行进一步的测试。 附 测试环境 操作系统:win10 硬盘:SSD 测试结果 子码流预览抓图,耗时毫秒级;主码流预览抓图,耗时10+毫秒级 预览抓图比设备拍图耗时少得多,设备抓图在100+毫秒级 在相同分辨率情况下,预览抓图的文件大小比设备抓图的略大

2021-12-15 11:29:07 · 1 分钟 · 慢步道人

配置Lazarus免重装

从其它平台迁移而来 事件 过了个十一,原本好好的电脑,突然鼠标不能用了,本着重启能解决80%的问题的原则重启了下,结果就杯具了,直接就蓝屏了,怎么折腾都进不了系统,BUG 10果然是BUG 10,绝对名不虚传! 无奈,只剩下重装系统这一条路了,装完系统之后还要装一堆软件,还要把软件配置成自己的习惯,还有其它一些细节工作……要把这些都做完才能大致恢复到原先的样子,想想就各种不爽。 虽然已经尽可能的使用免安装/重装的软件了,但还是避免不了有一些软件必须要重装才能使用的情况,唉~ 其中最令人头疼的就是开发环境了,几乎绝大部分都要重装,Lazarus就是其中之一,先前已经尝试过了,离成功只差一步了,这次终于搞定了,记录下来。 免重装 正常安装Lazarus 首次启动Lazarus会弹出初始配置界面,关闭 打开Lazarus的根安装目录,新建一个config文件夹 打开C:\Users\xxx\AppData\Local\lazarus文件夹(xxx为用户名),复制里面所有内容到config 找到Lazarus的快捷方式,右键属性,在目标里原有内容后面添加 --pcp=.\config(注意前面有空格),确定 把修改好的快捷方式复制到Lazarus的根安装目录下,供以后使用 删除C:\Users\xxx\AppData\Local\lazarus文件夹 使用刚才的快捷方式启动Lazarus,进行个性化设置、安装组件等 以后重装系统了直接使用快捷方式启动Lazarus即可 如果安装的组件全部都在Lazarus的安装目录下,整个Lazarus的安装目录即为一个便携式的IDE了 为避免如果使用过程中出现莫名其妙的现象,建议把Lazarus的安装目录下的ssleay32.dll、libeay32.dll、Qt5Pas1.dll和Qt4Pas5.dll复制到C:\Windows\System32或C:\Windows\SysWOW64下 本文参考了https://blog.csdn.net/love3s/article/details/7450339 附 在命令行进入Lazarus的根安装目录,运行lazarus.exe -? 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 lazarus [options] <project-filename> IDE Options: --help or -?...

2021-10-10 11:21:03 · 2 分钟 · 慢步道人