-2

Delphi 7 プロジェクトを XE4 に変換することにしましたが、コード行の 1 つで魔女の問題が発生し、修正しようとしましたが、希望がありませんでした。

問題は次のとおりです。

サーバーとクライアント アプリ (ホテル ルーム管理システム) の間で使用される共有ユニットでは、次のレコード タイプがあります。

      Type
      THotelClientDetails = packed record
      LSize:  Integer;
      ClientName:  array[0..25] of char;
      ClientRoomN:  Integer;
      RWithInternet: Boolean;
      RoomStatus    :Integer;
    //... etc 
      end;
          PHotelClientDetails = ^THotelClientDetails;

クライアント アプリでは、次の手順を使用します。

procedure TCForm.SendClientDetailsClick(Sender: TObject);
  var
  pClientDetails: PHotelClientDetails;
  iSize: Integer;
  begin

  iSize:= SizeOf(THotelClientDetails)+Length(ClientNameEd.Text)+1;
  GetMem(pClientDetails,iSize);
  ZeroMemory(pClientDetails,iSize);
  pClientDetails.LSize := iSize;
  StrCopy(pClientDetails.ClientName,PChar(ClientNameEd.Text));
  pClientDetails.ClientRoomN  :=StrToInt(ClientNEd.text);
  pClientDetails.RWithInternet:=ClientWInternet.Checked;
  pClientDetails.RoomStatus   :=ClientRoomStatus.ItemIndex;
  StrCopy(Pointer(Cardinal(pClientDetails)+SizeOf(THotelClientDetails)),
  PChar(ClientNameEd.Text));
  SendClientsBuffer(pClientDetails,iSize);// to the Server for Check
  FreeMem(pClientDetails);

  end;

サーバーアプリでは、次の手順を使用します。

Procedure TSForm.GetClientDetails(pClientDetails:PHotelClientDetails; Cntx: Pointer);
  var
  ClientName: string;
  begin
  ClientName:=PChar(Cardinal(pClientDetails)+SizeOf(THotelClientDetails));
  //*** just a test to get the ClientName
  ShowMessage(ClientName);
  //***
  end;

したがって、私の問題は、Delphi 7 を使用するときに、クライアント アプリから送信された完全な名前を取得することです。たとえば、クライアント "simon" または "matthew" をサーバーに送信する場合

私は正しい名前を取得します:

ShowMessage(ClientName);//simon or matthew

しかし、XE4 で同じプロシージャを使用すると、常に取得されます

サイモンの場合はsimマシュー の 場合はマット

これは、サーバーが Delphi7 プロジェクトのようにクライアントの完全な名前を受け取っていないことを意味します。

Both Projects にユニット「 System.AnsiStrings; 」が追加されていますが。

どうすればこの問題を解決できますか?

そして本当にありがとう。

サイモン

4

2 に答える 2

3

Delphi 7 は ANSI 文字列(シングルバイト文字)を使用しますが、2009 年以降のバージョンの Delphi は Unicode 文字列(マルチバイト文字)を使用します。

コードの最も簡単な修正は、Charから、 、およびに変更することです。AnsiCharstringAnsiStringPCharPAnsiChar

Type
  THotelClientDetails = packed record
    LSize:  Integer;
    ClientName:  array[0..25] of AnsiChar;
    ClientRoomN:  Integer;
    RWithInternet: Boolean;
    RoomStatus    :Integer;
    //... etc 
  end;

StrCopy(pClientDetails.ClientName, PAnsiChar(ClientNameEd.Text));
// and
StrCopy(Pointer(Cardinal(pClientDetails) + SizeOf(THotelClientDetails)),
        PAnsiChar(ClientNameEd.Text));

Procedure TSForm.GetClientDetails(pClientDetails:PHotelClientDetails; Cntx: Pointer);
var
  ClientName: string;
begin
  ClientName := PAnsiChar(Cardinal(pClientDetails)+SizeOf(THotelClientDetails));
  //*** just a test to get the ClientName
  ShowMessage(ClientName);
  //***
end;

ここには、D2007 以前から D2009 以降への Delphi コードの移植に関連する、文字通り数十 (数百ではないにしても) の質問があります。、およびタグをブラウジングするのに時間を費やす必要があります。

于 2013-08-31T23:53:46.597 に答える
1

質問へのコメントよりも書式設定が簡単なので、これを回答として投稿します。

あなたがやりたいかもしれないことについてのいくつかの発言:

  1. LengthDelphi 2009 以降での Unicode サポートでは、文字列の実際のバイト数が得られると想定しないでください。
  2. Delphi 7 と XE4 の間で、レコードに対する op メソッドの概念が導入されました (Delphi 2006 だと思います)。ロジックの一部SendClientDetailsClickをメソッドに移動THotelClientDetails
  3. THotelClientDetails.ClientNameは 26 バイト (25AnsiChar文字のバイトとヌル終端バイト) に制限されているため、Which
    iSize:= SizeOf(THotelClientDetails)+Length(ClientNameEd.Text)+1;
    iSize:= SizeOf(THotelClientDetails).
  4. ポインタを持っている唯一の理由は、 置き換えることができるものpClientDetails: PHotelClientDetailsを呼び出す ことですSendClientsBuffer(pClientDetails,iSize);// to the Server for Check

    SendClientsBuffer(ClientDetails,iSize);// to the Server for Check
  5. StrCopyではなく
    StrCopy(pClientDetails.ClientName,PChar(ClientNameEd.Text));
    Use StrLCopyで 25 バイトを超えるコピーを防止する長さガードはありません。
  6. ClientNameEdコピー アクションを2 回実行するのはなぜですか?
    StrCopy(pClientDetails.ClientName,PChar(ClientNameEd.Text));
    //...
    StrCopy(Pointer(Cardinal(pClientDetails)+SizeOf(THotelClientDetails)), PChar(ClientNameEd.Text));
  7. ポインタを主張する場合は、ブロックFreeMem内にある必要があります。finally

次のようなものがより適切です。

procedure TCForm.SendClientDetailsClick(Sender: TObject);
var
  ClientDetails: PHotelClientDetails;
  iSize: Integer;
begin
  iSize := SizeOf(THotelClientDetails);
  ZeroMemory(@ClientDetails, iSize);
  ClientDetails.LSize := iSize;
  StrLCopy(ClientDetails.ClientName, PAnsiChar(ClientNameEd.Text), SizeOf(ClientDetails.ClientName)-1);
  pClientDetails.ClientRoomN   := StrToInt(ClientNEd.text);
  pClientDetails.RWithInternet := ClientWInternet.Checked;
  pClientDetails.RoomStatus    := ClientRoomStatus.ItemIndex;
  SendClientsBuffer(@ClientDetails,iSize); // to the Server for Check
end;
于 2013-09-01T08:59:09.000 に答える