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 分钟 · 慢步道人

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 分钟 · 慢步道人

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 分钟 · 慢步道人

安装 CodeTyphon

从其它平台迁移而来 一直想找个开源的可以商用的Delphi的替代品,能跨平台了最好。开始时试过Lazarus,和D7还真是挺像的,不过用惯了XE,还是想找个习惯相似的IDE,扒拉下论坛后发现了CodeTyphon,就想着试一下。 下载 下载就不多说了,网上很容易找到,而且官方wiki写得也很好,英文好的可以直接看,像我这样的英语渣渣,还是有必要慢慢去啃的。 CodeTyphon下载后只有一个CodeTyphonIns.zip的压缩包,无论是Windows、Linux还是MacOS,安装包都是它,因为不管在哪个平台上安装,都是要编译的。 安装 解压CodeTyphonIns.zip得到CodeTyphonIns 在Windows平台,以管理员方式运行install.bat;在类unix平台,先cd CodeTyphonIns,再sudo ./install.sh 出现以下界面,输入0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 ==================================================== CodeTyphon Studio Version 7.30 (GEN 7) Installation for Linux-Solaris-Openindiana-MacOS FreeBSD-NetBSD-OpenBSD-DragonFly ==================================================== -----WARNING------ WARNING ----WARNING------- You tryng to install CT as root This is NOT the correct procedure. You MUST start CodeTyphon Installation as normal user with sudo root privileges --------------------------------------------- 0) Install CodeTyphon Studio (remove old first) 1) Update CodeTyphon Studio 2) Remove CodeTyphon Studio 9) Exit >>> Select an action (press 0....

2021-02-07 09:29:48 · 1 分钟 · 慢步道人

使用海康威视SDK的那些坑

从其它平台迁移而来 由于工作需要,项目中有使用到海康威视的产品,不可避免的就要使用海康的SDK进行二次开发。开发过程中磕磕绊绊的,踩了不少坑,这里做一个简单的记录,算是给健忘的自己提个醒吧。 Delphi版本的接口 Gitee地址 首先,自己一直使用Delphi进行开发,然而海康官方只提供了C/C++的接口和示例,无奈只能自己改写了。改写完的部分已经上传,希望能有人共同来完善。 由于Delphi商业使用的限制,现已转到Lazarus,全面拥抱开源。 坑 播放声音 预览时播放声音,回放时播放声音,甚至使用播放库播放已下载的视频时播放声音,这些对于前端摄像头自带麦克的场景肯定是刚需(另接麦克的情况暂未测试),然而按照官方SDK文档和示例代码写出的程序死活就是没有声音,这样的情况似乎不少人都遇到过,但是,好像并没有见谁把解决方法公开过。 其实,这个问题特别简单,只需要把HCNetSDKCom目录下的OpenAL32.dll拷贝到PlayCtrl.dll所在的目录下就可以了。这下就明白了吧,没有声音的原因其实就是使用NET_DVR_OpenSound调了PlayCtrl.dll,而PlayCtrl.dll又调了OpenAL32.dll来播放声音,但是由于PlayCtrl.dll没有找到OpenAL32.dll所以没有声音,而且这个有问题的返回值也并没有一层层的返回给NET_DVR_OpenSound函数,结果就是函数返回调用成功了,但就是死活没声音。 PlayCtrl.dll不是PlayCtrl.dll 使用海康SDK进行二次开发的,一般也会使用到海康的播放库,但是有一个问题是需要注意的,那就是SDK里的PlayCtrl.dll并不是播放库里的PlayCtrl.dll。虽然它们长得一样,名字也一样,但它们的本质却是完全不一样的,是不能互相替代的!有兴趣的朋友可以使用eXeScope详细查看。

2019-01-02 16:29:46 · 1 分钟 · 慢步道人