我的Delphi是XE(版本1,Update1).我正在使用Postgres生成葡萄牙语(葡萄牙语巴西)的错误消息,因此错误消息有重音符号.连接组件是ZeosLib包.
我正在使用一个对话框“reconcile error”来显示更新应用程序产生的错误并进行测试,我试图插入已经存在的记录,从而违反了一个唯一的密钥,从而显示了协调错误对话框.
在对话框的备忘录中,出现的消息被截断,即剪切.看看这个:
ERRO: duplicar valor da chave viola a restrição de unicidade "uc_usu_va_login" DETAIL: Chave (va_login)=(admin) já existe. CONTEXT: comando sql "INSERT INTO USUARIOS (VA_NOME,VA_LOGIN,CH
但实际应该返回的是:
ERRO: duplicar valor da chave viola a restrição de unicidade "uc_usu_va_login" DETAIL: Chave (va_login)=(admin) já existe. CONTEXT: comando sql "INSERT INTO USUARIOS (VA_NOME,CH_SENHA,VA_EMAIL) VALUES (pVA_NOME,pVA_LOGIN,pCH_SENHA,pVA_EMAIL)" PL/pgsql function "idu_usuarios" line 7 at comando sql
我在服务器上做了一个调试,看看问题是否是ZeosLib,但我发现服务器上生成的错误消息已经完成,证明ZeosLib没有截断消息.一切都是unicode.我的程序和ZeosLib中的所有字符串都是WideString(默认值).
如你所知,要抛出服务器,异常会被DataSnap转发给客户端,在客户端,TClientDataSet的Reconcile方法验证是否存在问题,然后抛出可能出现的着名异常EReconcileError.在TClientDataSet的OnReconcileError事件中处理,因此我认为该消息被DataSnap截断.
在客户端我调试Reconcile方法(DBClient.pas),并在抛出异常之前,流进入cpp源代码中的函数,我认为这是库midas.dll,MidasLib.obj的一部分更具体,因为我是使用此策略,不必使用我的应用程序分发DLL.
Check(FDSBase.Reconcile_MD(FReconcileDataSet.FDSBase,FDeltaPacket,VarToDataPacket(Results),Integer(Self),RCB));
此调用在Delphi XE Update1上的单元DBClient.pas的第1952行完成.按F7,调试器进入源C(cpp),所以我相信它在midaslib.obj中.我怎么不理解C,我按Shift-F8退出当前方法并返回下一条指令,即已经在事件OnReconcileError !!因此,截断必须在我提到的函数内,在一个cpp源中,在midaslib内完成.
我的目的是使Reconcile Error对话框不仅是最终用户的工具,而且是支持个人的工具,提供错误,详细信息和上下文的单独信息.这有助于发现问题.
现在的问题是使消息完整显示.消息被midas截断有没有人遇到过这种问题?
另外一点DSClient.pas我可以在传递给异常时提取错误消息:
'Erro sql: ERRO: duplicar valor da chave viola a restrição de unicidade "uc_usu_va_login"'#$A'DETAIL: Chave (va_login)=(admin) já existe.'#$A'CONTEXT: comando sql "INSERT INTO USUARIOS (VA_NOME'#$A',VA_LOGIN'#$A',CH'
如果删除引号并用空格(一个字符)替换#$A(1个字符),您将看到该字符串正好有255个字符!
我还发现dspickle.cpp中的“GetErrorString”使用常量DBIMAXMSGLEN,它在bdetypes.h中定义为127(255的一半).由于我们处于Unicode的世界中,为了每个字符有两个字节,将这个值增加到255不是一个问题吗?这只是猜测……
我把问题留在空中,因为我缺乏理解C的知识:)谁能提供帮助,只需看看dspickle.cpp中的函数实现“GetErrorString”.这有:
LoadString((HINSTANCE)hDll,iErrCode,pString,DBIMAXMSGLEN)
pString是错误消息,DBIMAXMSGLEN = 127.
解决方法
找到错误的一行之后,我发现甚至有一个QC(http://qc.embarcadero.com/wc/qcmain.aspx?d=84960)修理请求似乎被Embarcadero的工作人员忽略了,因为“决议”就是“推迟到Next Rel” (推迟到下一个版本),但请求是从2010年开始,我正在使用Delphi XE,在我看来应该有解决方案,但在这里我自己纠正;)
问题出在“DSBASE”类的方法“Clone”内,在第2133行(Delphi XE,Update1)的源“ds.cpp”内.下面是代码块.红线是有问题的线:
// Set the third field for the error string. LdStrCpy((pCHAR)pFldDes->szName,szdsERRMESSAGE); pFldDes->iFldType = fldZSTRING; pFldDes->iUnits1 = 255; // Increased on request.. DBIMAXMSGLEN; pFldDes++;
请注意问题行非常有趣.它的常量值为255,它限制了错误消息的大小和注释“根据请求增加”.还要注意,在注释旁边有一个常量DBIMAXMSGLEN,我已经找到并且已经怀疑它是否对该问题负责,但由于它没有被使用,我改变了DBIMAXMSGLEN的值但是错误消息总是没有变化.值得一提的是,在DBIMAXMSGLEN之后有一个分号(;)让我认为之前(我不知道什么时候)这行是我修复后的那一行:
pFldDes->iUnits1 = DBIMAXMSGLEN;
就好像有人故意将字段值设置为255,删除了之前真正动态且看似更正确的实现.在执行替换行之后,我将DBIMAXMSGLEN的值增加到1024.将DBIMAXMSGLEN声明为“bdetypes.h”作为定义.纠正线后像这样:
#define DBIMAXMSGLEN 1024 // Max message len
在“ds.cpp”和“bdetypes.h”中进行了这两个更改后,我构建,测试,结果与预期一致:错误消息在Reconcile对话框中完整显示.
对于想要尝试的勇敢者,如果他们已经看到了这个问题,你需要MIDAS的来源,如果我没记错的话,它将从2010年开始附带Delphi.祝你们好运.