ネットワークアダプタの一覧表示

解決


ペレ  2010-10-07 18:16:54  No: 39296

こちら  https://www.petitmonte.com/bbs/answers?question_id=529
を参考にネットワークアダプタの一覧を作ったのですが、
結果が一部文字化けするだけでなく変な内容が表示されてしまいました。

結果の抜粋:
ComboIndex: 1
AdapterName: 㡻㈶䅁㝄ⵁ㈳㤰㐭䘷ⴱ䑂䘵㔭ㄷ㈲㥄㈷㤷絁
Description: 
AddressLength: 0
Address: 0 0 0 0 0 0 0 0 
Index: 0
lngType: 0
DhcpEnabled: 0
CurrentIpAddress: 0
IpAddressList.Next: 0
IpAddressList.IpAddress.IpAddressString: 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 

原因が何かおわかりになる方いらっしゃいましたら、御教示ください。
よろしくお願いいたします。


ペレ  2010-10-07 18:19:23  No: 39297

[AdaptInfo.pas]は上記URLの物で[Unit1.pas]は下記の内容です。

// [AdaptInfo.pas]---------------------------------------------

unit Unit1;

interface

uses
  Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms,
  Dialogs, StdCtrls, AdaptInfo;

type
  TForm1 = class(TForm)
    Edit1: TEdit;
    Button1: TButton;
    Memo1: TMemo;
    procedure Button1Click(Sender: TObject);
  private
    { Private 宣言 }
  public
    { Public 宣言 }
  end;

var
  Form1: TForm1;

implementation

{$R *.dfm}

procedure TForm1.Button1Click(Sender: TObject);
var
     AdapterMem:PIPAdapterInfo;
     lngRes:LongInt;
     lngLen:integer;
     i:integer;
     STR:string;
begin
  lngRes := GetAdaptersInfo(nil, @lngLen);
  Edit1.Text:=IntToStr(lngRes);
  // 戻り値lngResでエラーチェック
  // ERROR_BUFFER_OVERFLOWだったらメモリを確保
  AdapterMem := GetMemory(lngLen);
  try
  lngRes := GetAdaptersInfo(AdapterMem, @lngLen);
  //Edit1.Text:=IntToStr(lngRes);
  Memo1.Lines.Clear;

  while AdapterMem <> nil do
  begin
    Memo1.Lines.Add('----------------------------------');
    Memo1.Lines.Add('Next: '+IntToStr(AdapterMem.Next));
    Memo1.Lines.Add('ComboIndex: '+IntToStr(AdapterMem.ComboIndex));
    Memo1.Lines.Add('AdapterName: '+AdapterMem.AdapterName);
    Memo1.Lines.Add('Description: '+AdapterMem.Description);
    Memo1.Lines.Add('AddressLength: '+IntToStr(AdapterMem.AddressLength));
    STR:='';
    for i:=0 to 7 do
      STR:=STR+IntToStr(AdapterMem.Address[i])+' ';
    Memo1.Lines.Add('Address: '+STR);
    {
    STR:='';
    for i:=0 to 7 do
      STR:=STR+IntToHex(AdapterMem.Address[i],2)+' ';
    Memo1.Lines.Add('Address: '+STR);
    }

    Memo1.Lines.Add('Index: '+IntToStr(AdapterMem.Index));
    Memo1.Lines.Add('lngType: '+IntToStr(AdapterMem.lngType));
    Memo1.Lines.Add('DhcpEnabled: '+IntToStr(AdapterMem.DhcpEnabled));
    Memo1.Lines.Add('CurrentIpAddress: '+IntToStr(AdapterMem.CurrentIpAddress));
    //IpAddressList
    Memo1.Lines.Add('IpAddressList.Next: '+IntToStr(AdapterMem.IpAddressList.Next));
    STR:='';
    for i:=0 to 15 do
      STR:=STR+IntToStr(AdapterMem.IpAddressList.IpAddress.IpAddressString[i])+' ';
    Memo1.Lines.Add('IpAddressList.IpAddress.IpAddressString: '+STR);
    STR:='';
    for i:=0 to 15 do
      STR:=STR+IntToStr(AdapterMem.IpAddressList.IpMask.IpMaskString[i])+' ';
    Memo1.Lines.Add('IpAddressList.IpMask.IpMaskString: '+STR);
    Memo1.Lines.Add('IpAddressList.Context: '+IntToStr(AdapterMem.IpAddressList.Context));
    //GatewayList
    Memo1.Lines.Add('GatewayList.Next: '+IntToStr(AdapterMem.GatewayList.Next));
    STR:='';
    for i:=0 to 15 do
      STR:=STR+IntToStr(AdapterMem.GatewayList.IpAddress.IpAddressString[i])+' ';
    Memo1.Lines.Add('GatewayList.IpAddress.IpAddressString: '+STR);
    STR:='';
    for i:=0 to 15 do
      STR:=STR+IntToStr(AdapterMem.GatewayList.IpMask.IpMaskString[i])+' ';
    Memo1.Lines.Add('GatewayList.IpMask.IpMaskString: '+STR);
    Memo1.Lines.Add('GatewayList.Context: '+IntToStr(AdapterMem.GatewayList.Context));
    //DhcpServer
    Memo1.Lines.Add('DhcpServer.Next: '+IntToStr(AdapterMem.DhcpServer.Next));
    STR:='';
    for i:=0 to 15 do
      STR:=STR+IntToStr(AdapterMem.DhcpServer.IpAddress.IpAddressString[i])+' ';
    Memo1.Lines.Add('DhcpServer.IpAddress.IpAddressString: '+STR);
    STR:='';
    for i:=0 to 15 do
      STR:=STR+IntToStr(AdapterMem.DhcpServer.IpMask.IpMaskString[i])+' ';
    Memo1.Lines.Add('DhcpServer.IpMask.IpMaskString: '+STR);
    Memo1.Lines.Add('DhcpServer.Context: '+IntToStr(AdapterMem.DhcpServer.Context));
    //
    Memo1.Lines.Add('HaveWins: '+IntToStr(AdapterMem.HaveWins));
    //PrimaryWinsServer
    Memo1.Lines.Add('PrimaryWinsServer.Next: '+IntToStr(AdapterMem.PrimaryWinsServer.Next));
    STR:='';
    for i:=0 to 15 do
      STR:=STR+IntToStr(AdapterMem.PrimaryWinsServer.IpAddress.IpAddressString[i])+' ';
    Memo1.Lines.Add('PrimaryWinsServer.IpAddress.IpAddressString: '+STR);
    STR:='';
    for i:=0 to 15 do
      STR:=STR+IntToStr(AdapterMem.PrimaryWinsServer.IpMask.IpMaskString[i])+' ';
    Memo1.Lines.Add('PrimaryWinsServer.IpMask.IpMaskString: '+STR);
    Memo1.Lines.Add('PrimaryWinsServer.Context: '+IntToStr(AdapterMem.PrimaryWinsServer.Context));
    //SecondaryWinsServer
    Memo1.Lines.Add('SecondaryWinsServer.Next: '+IntToStr(AdapterMem.SecondaryWinsServer.Next));
    STR:='';
    for i:=0 to 15 do
      STR:=STR+IntToStr(AdapterMem.SecondaryWinsServer.IpAddress.IpAddressString[i])+' ';
    Memo1.Lines.Add('SecondaryWinsServer.IpAddress.IpAddressString: '+STR);
    STR:='';
    for i:=0 to 15 do
      STR:=STR+IntToStr(AdapterMem.SecondaryWinsServer.IpMask.IpMaskString[i])+' ';
    Memo1.Lines.Add('SecondaryWinsServer.IpMask.IpMaskString: '+STR);
    Memo1.Lines.Add('SecondaryWinsServer.Context: '+IntToStr(AdapterMem.SecondaryWinsServer.Context));
    //
    Memo1.Lines.Add('LeaseObtained: '+IntToStr(AdapterMem.LeaseObtained));
    Memo1.Lines.Add('LeaseExpires: '+IntToStr(AdapterMem.LeaseExpires));
    // ループの最後で次の実体へのポインタを取得。最後であればnilが返ってくる
    AdapterMem:=Pointer(AdapterMem.Next);
  end;
  except
       ShowMessage('Error');
  end;
end;
end.
//[ここまで]---------------------------


s  2010-10-09 10:23:50  No: 39298

老婆心ですが、レスが付かないのは
動かないソースを貼り付けて問題点を探してください
という姿勢です。

> AdapterMem:=Pointer(AdapterMem.Next);
にブレークポイントを設定して、ウォッチウィンドウで
IPAdapterInfo構造体と定義しているAdapterMemを確認してみては
どうでしょう?

https://www.petitmonte.com/bbs/answers?question_id=7127
のリンク先では解決しているので、もう少しコードの理解を深めた方が
良いのでは?

オンラインのMSDNも読んだ方が良いです。
#IPAdapterInfo.ComboIndexは「Reserved」になっていて意味がある値では
ありません。


s  2010-10-09 21:05:03  No: 39299

http://www.hyuki.com/writing/techask.html
多分どれかに該当しています。


ペレ  2010-10-13 23:30:45  No: 39300

s老婆心さん
お叱り頂きありがとうございます。
それから返信が遅れましたことをお詫び致します。
誠にもっておっしゃる通りで、自ら解決しようとする姿勢の欠如に、
お恥ずかしい限りです。

落ち着いて、一つ一つ、進んでみようと思います。

さて、ご教示頂いたようにBPを設定してみました。
欲しい情報が何も取得できていない事がわかりましたので、
掘り下げて、iphlpapi.dll とその利用法を調べている所です。

そう言えば環境を書き忘れておりました。
Delphi 2010 proです。

何かわかりましたら、またここに報告したいと思います。
ありがとうございました。


Mr.XRAY  2010-10-14 01:18:27  No: 39301

こんにちは.Mr.XRAYです.
既にレスがありますが,
環境を書いていない質問なんて,「ほとんど冗談」ですね(笑)
雑談として発言するのであれば別ですが.

>Delphi 2010 proです。

ということですが,DelphiはDelphi 2009からUnicodeになりました.
したがって,それよりも前のバージョンで正常動作していたものも
修正が必要なことがあります.

リンクにあったにしのさんの,AdaptInfo.pas 内のコードはUnicode以前の
ものです.

TIPAdapterInfo構造体(レコード型)のCharの部分,

    AdapterName: array[0..MAX_ADAPTER_NAME_LENGTH + 4 - 1] of AnsiChar;//Char;
    Description: array[0..MAX_ADAPTER_DESCRIPTION_LENGTH + 4 - 1] of AnsiChar;// Char;
    
をAnsiCharに書き換えてみてください.
ペレさんの 2010/10/07(木) 09:19:23 のコードをそのままコピペして
実行したところ,文字化けはしていません.
この結果が意味のある結果かどうかは不明です.
また,他にも修正が必要が必要かも知れません.
今,ちょっと気になったところだけの修正です.

動作確認環境は,Windows XP(SP3) + Delphi 2010(UP5) Pro です.


Mr.XRAY  2010-10-14 01:53:35  No: 39302

それから

>それから返信が遅れましたことをお詫び致します。

反応が遅いのもレッドカードです.
なぜかは理解できると思いますが,質問に対して真剣がない,と
思われてしまいます.

>http://www.hyuki.com/writing/techask.html
>多分どれかに該当しています。

をお読みになっていると思われますので,追い討ちになってしまいますが,
念のため.


ペレ  2010-10-14 03:00:45  No: 39303

Mr.XRAYさん
私のような者にアドバイス頂きありがとう御座います(T_T)

お陰様で文字化けは解消できアダプタ名称が取得できました。
それ以外の値に関しては全くデタラメな値ばかりですが、
アダプタ名を取れただけでも大きな前進です。

BPを設置して何故IPアドレス等が取れないのか、
調べてみます。

ありがとうございました。


Mr.XRAY  2010-10-14 03:43:01  No: 39304

Unicode以前で動作していたコードであれば,たとえ修正が必要だとしても
必ず動作するようになるハズです.
Delphi 2007以前からDelphi 2009以後への移行は,少してこずることがあります.
私もはまったことがあります.
しかし,将来を考えるとUnicode化は避けられません.
がんばってください.

私のサイトからもたどれますが,DEKOさんの以下の場所から,unicode化,
あるいはDelphi 2009以降の情報とその関係リンクがあります.
参考になれば.

http://ht-deko.minim.ne.jp/Delphi/


D  2010-10-14 07:54:04  No: 39305

>お陰様で文字化けは解消できアダプタ名称が取得できました。
>それ以外の値に関しては全くデタラメな値ばかりですが、

私はDelphi 6なので2010だとまた違ってくるのかも知れませんが、

      STR:='';
      for i:=0 to 15 do begin
//        STR:=STR+IntToStr(AdapterMem.IpAddressList.IpAddress.IpAddressString[i])+' ';
        STR := STR + AnsiChar(AdapterMem.IpAddressList.IpAddress.IpAddressString[i]);
      end;
      Memo1.Lines.Add('IpAddressList.IpAddress.IpAddressString: '+STR);

のようにIntToStrをAnsiCharに変えたらIPアドレスが取れたのですが、そういうことではないのかな。


ペレ  2010-10-14 18:31:06  No: 39306

Mr.XRAYさん
そうですよね、それを聞いて安心しました。
色々調べて解決したいと思います。
ありがとうございました。

Dさん
まさにこれで解決しました。
とても助かりました。
ありがとうございました。


ペレ  2010-10-14 18:32:40  No: 39307

IntToStrでなくAnsiCharでないといけない理由について、
私なりに考えてみました。
もし間違っていたら、また御教示頂けると幸いです。
この度は大変勉強になりました。
ありがとうございました。

◆IntToStrでなくAnsiCharでないといけない理由
少し前の案件に出てきた、
https://www.petitmonte.com/bbs/answers?question_id=7129
> 「長さが 1 の文字列」は どの「文字型」とも互換性があり、
>  1文字だけの場合は「明示的に文字列」としないかぎり「文字定数」とみなされる
に該当する。

具体的には、
「AdapterMem.IpAddressList.IpAddress.IpAddressString[i]」の値が文字列長1であるために
「文字列の格納アドレス」にならず「文字の文字コード」になっているから、
IntToStrとすると文字コードの数値を文字列として格納してしまうため。


マラドーナ  2010-10-15 00:08:06  No: 39308

> IntToStrでなくAnsiCharでないといけない理由
その件には該当しません。何故ならそれは定数の話だからです。
今回のものは変数なので何の関係もありません。
(そもそもIpAddressString[i]は文字「列」ですらありません)
単純にAnsiCharとなるべきところがByte型として宣言されていただけの話です。

型はあくまでも「どう取り扱うか」であって、メモリ上ではどちらも中身は同じなので、
それをAnsiCharでキャストし、正しい扱いをしたために本来の結果が得られたということです。
つまり元のIP_ADDRESS_STRINGレコードを修正しても全く同じ結果が得られます。


ペレ  2010-10-15 02:06:15  No: 39309

マラドーナさん
ありがとうございました。

>型はあくまでも「どう取り扱うか」であって、メモリ上ではどちらも中身は同じなので、
>それをAnsiCharでキャストし、正しい扱いをしたために本来の結果が得られたということです。

理解できたような出来てないような...(‥ゞポリポリ

例えて言うなら、「文字コードUTF8として書かれた文字を、
Shift_JISとして扱って画面表示されたため、文字化けした」
と似たような事が起きていた...と理解して良いのでしょうね、きっと。

またまた勉強になりました。
ありがとうございました。


Mr.XRAY  2010-10-15 04:40:06  No: 39310

こんにちは.Mr.XRAYです.
こういう話にはあまり参入したくはないのですが,以下のコードを実行してみてください.

//----------------------------------------------------------------
//  AnsiCharとしているがDelphi 2009以降でもCharでも結果は同じ
//  なぜ同じになるかはDelphi 2009以降の文字あるいは文字列の扱い関
//  係の記事を参照
//----------------------------------------------------------------
procedure TForm1.Button2Click(Sender: TObject);
begin
  Memo1.Lines.Add(IntToStr($41));   //16進数の41は10進数では65.引数を整数として解釈している
  Memo1.Lines.Add(AnsiChar($41));   //16進数の41を文字にするとA.引数を文字として取り出している

  Memo1.Lines.Add(IntToStr($35));   //16進数の35は10進数では53
  Memo1.Lines.Add(AnsiChar($35));   //16進数の35を文字にすると5

  if AnsiChar($42) = 'B' then begin
    ShowMessage('同じだよ');
  end;
end;

>正しい扱いをしたために本来の結果が得られたということです。

というレスがありますが,これの補足です.
レスした方ゴメンなさいね.
ペレさんは,

>全くデタラメな値ばかりですが、

と書いていますが,これは違います.これも正しい値です.
前にレスした時は,「この結果が意味のある結果かどうかは不明です.」と書いたのは
ペレさんが望む結果が不明だからです.

上のコードの結果が理由です,つまり,単なる結果に対する表現の違いです.
過去に,この掲示板か,どこかのコミュニティで,ペレさんの言う
「デタラメな値」を取得したいという方もいました.
人によって,
「これこれになるようにしたい」
という人がいる反面,
「これこれにならないようにならないようにしたい」
という人もいるということです.

Charは汎用の文字型です.

http://docwiki.embarcadero.com/RADStudio/ja/Char
http://docwiki.embarcadero.com/VCL/ja/System.AnsiChar


Mr.XRAY  2010-10-15 04:42:22  No: 39311

>Charは汎用の文字型です.

文字「列」ではありません.念のため.


ペレ  2010-10-15 19:45:53  No: 39312

Mr.XRAYさん
ありがとうございました。(T_T)

デタラメという表現は間違っていましたね。
そして示して頂いたコードできちんと理解できたように思います。

値を変換する際、「引数をどう扱い、どう変換するか」に注意する必要がある。

大変勉強になりました。
ありがとうございました。


※返信する前に利用規約をご確認ください。

※Google reCAPTCHA認証からCloudflare Turnstile認証へ変更しました。






  このエントリーをはてなブックマークに追加