2

Delphi を使用して DEV_BROADCAST_PORT からフレンドリ名 (dbcp_name) を取得する際に問題が発生しています。

ヌル終了文字列へのポインタであると書かれているマイクロソフトのヘルプ ドキュメントを使用してみましたが、そのページには可変長構造であることを示すコメントがあり、dbcp_name は実際の文字列を含む配列です。ポート名。

私はこれを抽出しようとしましたが、何かを返すようにすると完全に意味不明になるため、現在のところ方法が見つかりません。

私が使用したコードは次のとおりです。

PDevBroadcastPort = ^DEV_BROADCAST_PORT;

DEV_BROADCAST_PORT = packed record
    dbcp_size : DWORD ;
    dbcp_devicetype : DWORD;
    dbcp_reserved : DWORD ;
    dbcp_name : array[0..0] of ansichar; //TCHAR dbcp_name[1]; not valid
end;

配列の長さに対してさまざまな値を試しました。これが正しい宣言であることをどこかで読んだことがありますが、完全にはわかりません。また、コメントアウトされた行は、MicrosoftドキュメントがC ++の行に提供するものです

私がこれを試した情報を抽出するには:

var
  PData: PDevBroadcastPort;

  FName: string;

  ...

  PData := PDevBroadcastPort(Msg.lParam);

  ShowMessage('Length '+Inttostr(length(PData^.dbcp_name)));

  FName := '';

  i:=0;

  while((PData^.dbcp_name[i]) <> #0) and (i < 100) do
      begin
          FName := FName + (PData.dbcp_name[i]);

          i := i +1;

          ShowMessage(FName); 
      end;

データ構造の長さで終了するようにwhileループを設定しようとしましたが、設定しないと巨大になります。

この質問に必要なコードを省略した場合はお知らせください。できるだけ早く取得します。

ありがとう

4

2 に答える 2

4

ドキュメントには、null で終わる文字列へのポインターであるとは記載されていません。null で終わる文字列であると表示されますこれは、長さが 1 つの要素だけのレコードの最後で宣言されている配列の場合によく見られます。

実際には、指定されたレコード サイズよりも多くのメモリがあり、そのメモリには文字列の残りの文字が保持されます。そのレコード フィールドへのポインターは、文字データへのポインターでもあります。

FName := PAnsiChar(@PData.dbcp_name);

そのコードの範囲に対して境界チェックを無効にしていると仮定すると、配列をトラバースするコードも機能するはずです (そうしないと、プログラムが配列の最初の要素を超えて読み取りを検出したときに例外が発生します)。

PDataそれはすべて、それが実際に構造体へのポインターであることを前提としていますDev_Broadcast_Port。あなたが手渡したメッセージについての情報を提供していないので、あなたが持っていると思っているものを本当に持っているかどうかはわかりません.

Delphi 2009 以降を使用している場合TCHAR、C 宣言の型は Delphi の型と同等WideCharです。フィールドを の配列として解釈すると、AnsiChar誤った結果が得られますが、ほとんどのポート名では、配列が null で終わる 1 文字の文字列のリストであるかのように見える場合があります。非 Unicode データがあることが確実でない限り、 and のみを使用CharPChar、Delphi のバージョンにどのデータ型があるかを判断させてください。

FName := PChar(@PData.dbcp_name);
于 2012-07-20T13:19:20.107 に答える
0

dbcp_nameフィールドには実際の文字が含まれています。null ターミネータを引いた文字データの長さはdbcp_size - SizeOf(DEV_BROADCAST_PORT)であるため、次のように名前を取得できます。

type
  DEV_BROADCAST_PORTA = packed record
    dbcp_size : DWORD;
    dbcp_devicetype : DWORD;
    dbcp_reserved : DWORD;
    dbcp_name : array[0..0] of AnsiChar;
  end; 

  DEV_BROADCAST_PORTW = packed record
    dbcp_size : DWORD;
    dbcp_devicetype : DWORD;
    dbcp_reserved : DWORD;
    dbcp_name : array[0..0] of WideChar;
  end; 

  {$IFDEF UNICODE}
  DEV_BROADCAST_PORT = DEV_BROADCAST_PORTW;
  {$ELSE}
  DEV_BROADCAST_PORT = DEV_BROADCAST_PORTA;
  {$ENDIF}
  PDEV_BROADCAST_PORT = ^DEV_BROADCAST_PORT;

.

var
  PData: PDEV_BROADCAST_PORT;
  FName: string;

...
PData := PDEV_BROADCAST_PORT(Msg.lParam);
SetString(FName, PData^.dbcp_name, (PData^.dbcp_size - SizeOf(DEV_BROADCAST_PORT)) div SizeOf(Char));
ShowMessage(FName);
于 2012-07-20T20:00:02.340 に答える