其实很早就打算在Lazarus里面做一个,要么在实际应用中时间太紧需要使用OPC了就用Delphi的程序改改,也就用了。
到了FPC3.0之后也就lazarus1.6以后,其核心对UTF8的全面支持,导致Delphi的很多程序都不能直接转移到Lazarus里面。明知山有虎偏向虎山行,OPC里面会大量用到PWideChar和OleVariant这是难点,本身技术上倒不是,但与Lazarus的融合就存在很多不不确定性。
OPC客户端的构建流程很简单
- 建立ActiveX服务器的引用
- 通过服务器接口的“组管理器”——构建组
- 通过组的条“目管理器”在该组添加“条目”,也就是工业领域说的“标签”——Tag
- 现在可以Read/Write读写标签了
- 如果希望效率,OPC提供的托管方式,也就是常常翻译为“订阅”的方法。以组为单位构建“订阅”。
- 如果成功将实现 OnChange 、AsyncRead、AsyncWrite (异步读写)。
期间每一步都要注意资源的释放!而且每一步又都要与字符串打交道,注意COM内部大量使用WideString,但微软的大师在设计自然是会大量用到指针的,所以PWideChar与FPC的String的交互就成了主要任务。关键问题字符串,不彻底解决就算构建成功也不能正常显示,更何况由于Lazarus的内部转换,基本就是构建不成功。
RTL,LCL默认都是UTF8这是有优势的,但很难驾驭,这也导致很多lazarus1.2x之前的很多解决方案失效,比如SysToUTF8和UTF8ToSys,跟踪发现
function UTF8ToSys(const s: string): string; begin {$IFDEF UTF8_RTL} Result:=s; {$ELSE} if NeedRTLAnsi and (not IsASCII(s)) then Result:=UTF8ToAnsi(s) else Result:=s; {$ENDIF} end; 注意这里面的条件编译{$IFDEF UTF8_RTL}
导致这些过程\函数\方法有时候“生效”有时候“无效”主要是条件编译{$IFDEF UTF8_RTL}的作用,其实上次发的博文提到的FPC 3.0 增加-dDisableUTF8RTL项目编译选项,使参数保存在本项目里面。当配置完毕以上语句就可以执行到{$ELSE} 部分了。
整个现象这个让我懊恼了好久好久,总是不能明确结果,导致Lazarus程序字符串输出不能达到预期的效果,用了好多方法,甚至怀疑是否真的该放弃当时自己写的UTF8转换单元,使用系统自带功能的判断。幸好手头有两个项目一个有这个参数一个没有,结果导致截然不同的效果,当然有一个能准确实现设计意图否则也就不会去分析了——庆幸。最后还是看了[Lazarus] UTF8 RTL for Windows才想起。
方向明确了之后,要解决问题自然就是找出具体的办法处理字符串。
我们对待POleChar通常的解决办法是 PWchar(WideString(XXXstring));在Lazarus里面小工程例子项目没有问题,大了,也就是资源使用比较多也许到用的时候早就释放了。就必须用到StringToOleStr(XXXstring)了。
整合后得到如下过程函数
function UTF8StrToOleStr(const Source: UTF8String): PWideChar; var vS: string; begin vS := UTF8ToSys(Source); // Result := POleStr(WideString(vS)); Result := StringToOleStr(vS); if Result = nil then Result := ‘‘; end; function OleStrToUTF8Str(const Source: PWideChar): UTF8String; var vS: string; begin if Source = nil then Result := ‘‘ else WideCharToStrVar(Source, vS); Result := SysToUTF8(vS); end;
现在记性太不好了,做个记录。