Delphi 2009和复制内存

时间:2009-03-06 18:24:05

标签: delphi memory delphi-2009

我在Delphi 2009上测试DelphiModbus library并没有得到我想要的结果。我认为问题在于IdModbusClient.pas上的以下行:

Move(Buffer, ReceiveBuffer, iSize);

看起来像ReceiveBuffer设置为垃圾。

缓冲区定义为TIdBytes(来自Indy组件)

ReceiveBuffer定义为TCommsBuffer:

  TModBusFunction = Byte;

  TModBusDataBuffer = array[0..256] of Byte;

  TCommsBuffer = packed record
    TransactionID: Word;
    ProtocolID: Word;
    RecLength: Word;
    UnitID: Byte;
    FunctionCode: TModBusFunction;
    MBPData: TModBusDataBuffer;
    Spare: Byte;
  end; { TCommsBuffer }

iSize当然是缓冲区的大小,以字节为单位。

我想知道这是否与unicode转换有关?

2 个答案:

答案 0 :(得分:4)

Indy的TIdBytes类型是动态数组,在 IdGlobal.pas 中定义:

type
  TIdBytes = array of Byte;

您不能将该类型的变量直接传递给Move并期望它能够正常工作,因为它只会复制存储在该变量中的四字节引用。 (如果你告诉它复制超过四个字节,那么它将继续复制该变量之后驻留在内存中的任何其他东西 - 谁知道什么。)给出这些声明:

var
  Buffer: TIdBytes;
  ReceiveBuffer: TCommsBuffer;

在这些变量上调用Move的方法如下:

if Length(Buffer) > 0 then
  Move(Buffer[0], ReceiveBuffer, iSize);

它之类似,因为Move的参数是untyped,因此您需要传递要复制的,而不是指针或引用值。编译器自己处理引用。

代码有点奇怪,因为它看起来像你只是从Buffer复制一个字节,但是不要让它太烦人了。这是德尔福的成语;它只是它的工作方式。

此外,这与Delphi 2009无关;自Delphi 4推出动态数组以来,它一直以这种方式工作。 Move永远是这样的。

答案 1 :(得分:1)

在我看来,你错过了几个指针解引用,因此破坏了内存地址。

<击>

如果我没弄错的话,Move()调用应该是:

<击> Move(Buffer^, ReceiveBuffer^, iSize);

I've removed my totally worthless post content (leaving it for posterity and to give someone a good laugh).

I don't see anything that would be affected by Unicode at all. I'm going to edit the tags to include Delphi (without the 2009), as some of the CodeGear Delphi developers are currently posting there. Perhaps one of them can see what's happening.

I made up a contrived example (actually a pretty useless one):

uses
  IdGlobal;

type
  TModBusFunction = Byte;
  TModBusDataBuffer = array[0..256] of Byte;

  TCommsBuffer=packed record
    TransactionID: Word;
    ProtocolID: Word;
    RecLength: Word;
    UnitID: Byte;
    FunctionCode: TModBusFunction;
    MBPData: TModBusDataBuffer;
    Spare: Byte;
  end;

procedure TForm1.FormShow(Sender: TObject);
var
  Buffer: TIdBytes;
  ReceiveBuffer: TCommsBuffer;
  //iSize: Word;
begin
  FillChar(ReceiveBuffer, SizeOf(ReceiveBuffer), 0);
  ReceiveBuffer.TransactionID := 1;
  ReceiveBuffer.ProtocolID := 2;
  ReceiveBuffer.RecLength := 3;
  ReceiveBuffer.UnitID := 4;
  ReceiveBuffer.FunctionCode := 5;
  FillChar(ReceiveBuffer.MBPData[0], SizeOf(ReceiveBuffer.MBPData), 6);
  ReceiveBuffer.Spare := 7;
  SetLength(Buffer, SizeOf(ReceiveBuffer));
  Move(ReceiveBuffer, Buffer, SizeOf(ReceiveBuffer));
  Move(Buffer, ReceiveBuffer, SizeOf(ReceiveBuffer));
  ReceiveBuffer.UnitID := 8;
end;

然后我在结束前的最后一行设置一个断点,然后运行它。当断点被击中时,我使用ToolTip Evaluation查看了ReceiveBuffer的内容,一切看起来都很好。我可以看到所有正确的值,包括ReceiveBuffer.Spare为7.然后我单步,看看ReceiveBuffer.UnitID;它实际上的值为8.

然而,按F9继续运行(期望能够关闭表单并结束应用程序),我最终进入CPU窗口并从Vista收到一条消息,表明应用程序没有响应。我刚刚在ntdll.DebugBreakPoint,IIRC之外,单步进入ntdll.RtlReportException。我不太确定发生了什么,但这并不好。还在看。

Edit2:我再次运行它,结果相同。但是,这次我注意到之前我使用Ctrl + F2来终止应用程序,Vista正在给我一个弹出式工具栏窗口,指示“Project1.exe已关闭”并提及DEP(我已在此机器的硬件中启用)。