2009-03-06 18 views
2

Delphi 2009でDelphiModbus libraryをテストしていますが、私が望む結果が得られません。私はこの問題はIdModbusClient.pasに以下の行であると思う:Delphi 2009とメモリのコピー

Move(Buffer, ReceiveBuffer, iSize); 

ReceiveBufferが何らかのごみに設定されているように見えます。

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はバイト単位もちろんバッファのサイズである:

バッファは

ReceiveBufferをTCommsBufferとして定義される(インディ成分から)TIdBytesとして定義されます。

これはユニコード変換と関係がありますか?

+0

私はあなたが* destination * sizeを移動するバイト数として常に使用することをお勧めします。そうしないと、何らかの理由で誰かが大きなソースバッファを渡すことができれば、関連するすべてのリスクで宛先バッファをオーバーフローさせる可能性があります。 –

答えて

4

Indy's TIdBytesタイプはIdGlobal.pasで定義され、動的配列でありますそのタイプの変数を直接Moveに設定し、その変数に格納されている参照の4バイトのみをコピーするため、その変数が動作することを期待します。 (5つ以上のバイトをコピーすることを告げたなら、それはその変数の後にメモリに常駐する任意の他のコピーに進みます - 誰が何を知っている。)これらの宣言を考える:

var 
    Buffer: TIdBytes; 
    ReceiveBuffer: TCommsBuffer; 

Moveを呼び出す方法これらの変数は、このようなものです:Moveのパラメータがuntypedをしているので、あなたがコピーしたい、値ではないポインタまたは参照を渡す必要があるため

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

それはそのように動作します。コンパイラは、参照自体を処理します。

のように見えますが、Bufferから1バイトだけコピーしていますが、あまり気にしないようにしてください。それはDelphiのイディオムです。それはちょうどそれが動作する方法です。

また、これはDelphi 2009とは関係ありません。動的配列が導入されたDelphi 4以降、これまでどおりこの方法で動作します。そしてMoveは永遠にこの方法です。

+0

ありがとうございます。そのライブラリがIndy 10で動作していたのだろうか。私は後でテストする必要があります。 – Harriv

1

私はあなたに2つのポインタ逆参照が足りなくてメモリアドレスが壊れているように見えます。私は間違っていない場合は

、移動()の呼び出しは次のようになります。

type 
    TIdBytes = array of Byte; 

あなたが渡すことはできません。

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; 

I then set a breakpoint on the last line before the end, and ran it. When the breakpoint was hit, I looked at the contents of ReceiveBuffer using ToolTip Evaluation, and everything looked perfectly fine. I could see all of the proper values, including the ReceiveBuffer.Spare being 7. I then single stepped, and looked at ReceiveBuffer.UnitID; it in fact had a value of 8.

However, pressing F9 to continue running (expecting to be able to just close the form and end the application), I ended up in the CPU window and got a message from Vista that the application wasn't responding. I was just outside ntdll.DebugBreakPoint, IIRC, and single stepping brought me into ntdll.RtlReportException. I'm not quite sure what's happening, but it ain't good. Still looking.

Edit2: I ran it again, with the same results. However, this time I noticed before I used Ctrl+F2 to terminate the app that Vista was giving me a popup tooltray window indicating that "Project1.exe has been closed" and mentioning DEP (which I have enabled in hardware on this machine).

+0

コンパイルできません、エラーメッセージ:[DCCエラー] IdModBusClient.pas(296):E2017ポインタタイプが必要です – Harriv

+0

あなたは絶対に正しいです。投稿する前に私にゆっくりと読むように教えてください。私はそれほど愚かではないように見える。 :-( TModBufDataBufferとTModBusFunctionはどのように定義されていますか? –

+0

これらは単なるバイト、1バイトと配列です。元の質問を編集しました。 – Harriv

関連する問題