德尔福 - 程序无法完成,但与" showmessage"之间。?

时间:2014-03-18 01:03:39

标签: delphi

我不太确定如何提出这个问题,因为我不知道它是否与执行时间,申请流程,消息程序或其他任何内容有关。

我(对我来说)奇怪的情况,程序无法运行并在运行时引发系统异常,而如果我把" showmessage"它运行完全完美无瑕。介于两者之间(我把它放在一起,以便我可以很快看到它们之间发生了什么。我更喜欢这种方式而不是以某种方式......)。

我不确定代码是否重要,但我会在下面给出:

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; external' bin \ settings.txt';

这是在dll中:

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 changing Chars in string - missunderstood behavior - XE3的问题中进行了讨论,并在Remy的答案中使用。 DecodeChar,我相信在这里根本不重要,或者是它?

此外,保存设置的功能也是如此,在FormClose事件中调用:

这是:

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放在那里就会消失。

(函数编码基本上是解码的镜像,所以代码在这里并不重要......)

3 个答案:

答案 0 :(得分:3)

这段代码在很多层面都非常危险。以不安全的方式跨DLL边界使用对象。跨函数调用的对象指针管理不善。你需要重新设计。尝试以下作为开始:

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;

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;

答案 1 :(得分:1)

这里显而易见的问题是代码存在于DLL中。很可能你没有安排DLL共享它的主机堆。并且Delphi类不能跨DLL边界传递。

如果要在模块之间共享Delphi类,则必须使用包。当然,另一种选择是将所有代码放在同一个模块中。那就是删除DLL,并编译可执行文件中的所有内容。最后一个选项是为DLL使用有效的互操作类型。

当然,实际错误可能还有其他原因。代码闻起来很糟糕。例如,这是什么:

DecodeBuffer:=Buff;

DecodeBuffer是全局变量吗?如果是这样,那么在物体被摧毁后引用它是合理的。并不是说我能看到任何被破坏的证据。不希望看起来粗鲁,你的代码看起来可能有多个问题。作为紧急事项,您需要:

  1. 处理上述DLL问题。
  2. 删除全局变量。
  3. 修复生命周期问题。停止泄漏。
  4. 启用范围检查以查找缓冲区溢出。
  5. 在调试模式下添加FastMM以尝试捕获堆损坏。

答案 2 :(得分:0)

我想我知道这里发生了什么:我认为你的筹码正在被粉碎。

此外,我更怀疑实际原因是使用未初始化变量的Decode过程。你的ShowMessage语句(如果我正确的话,它将是第一个重要的)改变堆栈上的内容,从而改变未初始化的变量。

如果我说得对,这会产生一些heisenbug属性 - 你所做的任何事情都会改变未初始化变量的值。

要尝试的一件事:声明一个大的局部变量(想法是用尽堆栈空间)并确保它不会被编译器丢弃。这将把事情转移到记忆中,从而可能化解爆炸。如果它起作用,它对于正在发生的事情非常有把握。