Delphi - procedure fails to complete, but works fine with “showmessage” between.?
我不太确定如何问这个问题,因为我不知道它是否与执行时间,应用程序进程,消息程序或其他任何内容有关。
我(对我来说)奇怪的情况,程序无法运行并在运行时引发系统异常,而如果我在其间放置"showmessage",它完全无故障运行(我这样做,以便我可以很快看到会发生什么介于两者之间。我更喜欢这种方式而不是手表...)。
我不确定代码是否重要,但我会在下面给出:
1 2 3 4 5 6 7 8 9 10 | procedure LoadSettings; var SettingsBuffToLoad: TStringList; begin SettingsBuffToLoad:=TStringList.Create; Encoding:=TEncoding.ANSI; SettingsBuffToLoad.LoadFromFile('bin/settings.txt', Encoding); // showmessage(settingsbufftoload.Strings[0]); SettingsBuffer:=Decode(SettingsBuffToLoad); // showmessage(settingsbuffer.Strings[0]); //decode end; |
解码过程声明为外部,并从dll读取。
如果我只删除那些"/",以便它成为代码而不是注释,它就可以正常工作。但是,按照您现在的设置,它会引发异常,但在该过程已经完成之后。 (调试器的最后一个断点在"end;"处停止,然后继续它会引发异常而不是显示表单;此过程在FormCreate过程中被调用为最后一个。
有没有什么与时间有关,ShowMessage解决了,还是......? :/
更新:
解码函数,如下所述:
这是它的声明方式,正好在表单的实现和变量之上:
function Decode(Buff:TStringList):TStringList; STDCALL;外部'bin settings.txt';
这是在DLL中:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 | function Decode(Buff: TStringList): TStringList; export; var t, u, h: integer; s: String; begin DecodeBuffer.Clear; DecodeBuffer:=Buff; for h := 0 to DecodeBuffer.Count-1 do begin s := DecodeBuffer.Strings[h]; t := Length(s); if t > 0 then begin for u := 0 to t-1 do begin s[u+1] := DecodeChar(s[u+1], (h mod 5) + 1); end; DecodeBuffer.Strings[h] := s; end; end; Result:=DecodeBuffer; end; |
这个代码在Delphi的一个问题中进行了讨论,在字符串中更改了Chars - 错误理解的行为 - XE3,并使用了Remy的答案。 DecodeChar,我相信在这里根本不重要,或者是它?
此外,保存设置的功能也是如此,在FormClose事件中调用:
这是:
1 2 3 4 5 6 7 8 9 10 | procedure TScribbles.SaveSettings; var SettingsBuffToSave: TStringList; begin SettingsBuffToSave:=TStringList.Create; Encoding := TEncoding.ANSI; // Showmessage(settingsbuffer.Strings[0]); SettingsBuffToSave:=Encode(SettingsBuffer); // Showmessage(settingsbufftosave.Strings[0]); SettingsBuffToSave.SaveToFile('bin/settings.txt', Encoding); end; |
第一个ShowMessage用作代码而不是注释,它可以工作,而在上面写的注释函数中,它以与Decode相同的方式调用外部异常。
是否有可能,当它已经调用函数Encode时,尚未创建SettingsBuffToSave,或者是什么?
那时,SettingsBuffer存在并被填充,所以它引发错误似乎很奇怪,只需将ShowMessage放在那里就会消失。
(函数编码基本上是解码的镜像,所以代码在这里并不重要......)
这段代码在很多层面都非常危险。以不安全的方式跨DLL边界使用对象。跨函数调用的对象指针管理不善。你需要重新设计。尝试以下作为开始:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 | procedure Decode(Buff: PChar; BuffLen: Integer; ListIndex: Integer); stdcall; export; var u: integer; begin for u := 0 to BuffLen-1 do begin Buff^ := DecodeChar(Buff^, (ListIndex mod 5) + 1); Inc(Buff); end; end; procedure Encode(Buff: PChar; BuffLen: Integer; ListIndex: Integer); stdcall; export; var u: integer; begin for u := 0 to BuffLen-1 do begin Buff^ := EncodeChar(Buff^, (ListIndex mod 5) + 1); Inc(Buff); end; end; |
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 | procedure Decode(Buff: PChar; BuffLen: Integer; ListIndex: Integer); stdcall; external '...'; procedure Encode(Buff: PChar; BuffLen: Integer; ListIndex: Integer); stdcall; external '...'; procedure LoadSettings; var h: Integer; begin SettingsBuffer := TStringList.Create; SettingsBuffer.LoadFromFile('bin/settings.txt', TEncoding.ANSI); for h := 0 to SettingsBuff.Count-1 do begin Decode(PChar(SettingsBuff[h]), Length(SettingsBuff[h]), h); end; end; procedure TScribbles.SaveSettings; var h: Integer; begin for h := 0 to SettingsBuff.Count-1 do begin Encode(PChar(SettingsBuff[h]), Length(SettingsBuff[h]), h); end; SettingsBuff.SaveToFile('bin/setpb95enc.dll', TEncoding.ANSI); end; |
这里显而易见的问题是代码存在于DLL中。很可能你没有安排DLL来共享它的主机堆。并且Delphi类不能跨DLL边界传递。
如果要在模块之间共享Delphi类,则必须使用包。当然,另一种选择是将所有代码放在同一个模块中。那就是删除DLL,并编译可执行文件中的所有内容。最后一个选项是为DLL使用有效的互操作类型。
当然,实际错误可能还有其他原因。代码闻起来很糟糕。例如,这是什么:
1 | DecodeBuffer:=Buff; |
我想我知道这里发生了什么:我认为你的筹码被粉碎了。
此外,我更怀疑实际原因是使用未初始化变量的Decode过程。您的ShowMessage语句(如果我是正确的话,它将是第一个重要的)更改堆栈中的内容,从而更改未初始化的变量。
如果我是对的,这将有一些heisenbug属性 - 你做的任何事情,以找出正在发生的事情将改变未初始化的变量的价值。
要尝试的一件事:声明一个大的局部变量(想法是用尽堆栈空间)并确保编译器不会丢弃它。这将把事情转移到记忆中,从而可能化解爆炸。如果它有效,它对于正在发生的事情是非常确定的。