プロが教えるわが家の防犯対策術!

はじめまして、sandayu999と申します。

ネットワークアダプタの情報を取得するために
GetAdapterInfo関数を使用しているのですが
返り値がエラーとなってしまいます。

環境はWindowsXPでCコンパイラは
borlandのbcc32.exeを使用しております。
コンパイルは正常に行えました。

[mac.c]
---------------------------------------
IP_ADAPTER_INFO adapterInfo;
DWORD aiSize;

GetAdaptersInfo(NULL,&aiSize); //サイズ取得

print("%d\n",GetAdaptersInfo( &adapterInfo, &aiSize ));

出力してみたところ、値が87(ERROR_INVALID_PARAMETER)
となってしまいました。

どのような対処をしたら良いのかわからない状態です、どなたかアドバイスをよろしくお願いいたします。

A 回答 (6件)

PIP_ADAPTER_INFO padapterInfo;


DWORD aiSize;

GetAdaptersInfo(NULL,&aiSize);
padapterInfo=(PIP_ADAPTER_INFO)malloc(aiSize);

printf("%d\n",GetAdaptersInfo( padapterInfo, &aiSize ));
free(padapterInfo);
でどうでしょう?
質問文のソースではアダプタが1つの時にしか正常に動作しないような気がします。

この回答への補足

hofuhofuさん、taka_tetsuさん返信ありがとうございます。

>taka_tetsuさん
>書かれているコード、質問に書かれた部分で全部ですか?
すみません、一部しか記述しておりませんでした。
全体は下記になります(多少みずらくなってます)
-----------------
#include <windows.h>
#include <iphlpapi.h>
#include <stdio.h>

void main(void){
IP_ADAPTER_INFO adapterInfo;
DWORD aiSize, i;
GetAdaptersInfo(NULL,&aiSize);

if( GetAdaptersInfo( &adapterInfo, &aiSize ) != ERROR_SUCCESS )
{
printf( "GetAdapterInfo呼び出し失敗\n" );
return;
}

fprintf( stdout,"MACアドレス = [" );
for( i = 0; i < adapterInfo.AddressLength; i++ )
{
fprintf( stdout, "%.2X", (int)adapterInfo.Address[i] );

if( i == ( adapterInfo.AddressLength - 1 ) )
fputs( "]\n", stdout );
else
fputs( "-", stdout );
}
}

そこで、hofuhofuさんのご指摘通りに行ってみたところ、
-----------------
PIP_ADAPTER_INFO padapterInfo;
DWORD aiSize;

GetAdaptersInfo(NULL,&aiSize);
padapterInfo=(PIP_ADAPTER_INFO)malloc(aiSize);

printf("%d\n",GetAdaptersInfo( padapterInfo, &aiSize ));
free(padapterInfo);

にて成功の0が出力されました。

これはIP_ADAPTER_INFOのポインタ型のPIP_ADAPTER_INFOを使用することでNIC分のメモリを
確保しているという解釈でよいでしょうか?
(IP_ADAPTER_INFOだと、一つ分しか確保できていなかった)
そこで、プログラムを下記のように直してみました。

-----------------
#include <windows.h>
#include <iphlpapi.h>
#include <stdio.h>

void main(void){
PIP_ADAPTER_INFO padapterInfo;
DWORD aiSize, i;

GetAdaptersInfo(NULL,&aiSize);

if( GetAdaptersInfo( padapterInfo, &aiSize ) != ERROR_SUCCESS )
{
printf( "GetAdapterInfo呼び出し失敗\n" );
return;
}

while( padapterInfo )
{
fprintf( stdout,"MACアドレス = [" );
for( i = 0; i < padapterInfo->AddressLength; i++ )
{
fprintf( stdout, "%.2X", (int)padapterInfo->Address[i] );

if( i == ( padapterInfo->AddressLength - 1 ) )
fputs( "]\n", stdout );
else
fputs( "-", stdout );
}
padapterInfo = padapterInfo->Next;
}
free(padapterInfo);
}
[結果]
-----------------
MACアドレス = [00-xx-xx-xx-xx-xx]
MACアドレス = [00-xx-xx-xx-xx-xx]
MACアドレス = [00-xx-xx-xx-xx-xx]

と無事MACアドレスが出力されました。

雑誌にはもともとのソースでもNIC1枚分の情報は出力
されるとあったのですが、現在の方法
での処理のほうが正しいようです。

それと、MSDNのサンプルでは
http://msdn.microsoft.com/library/default.asp?ur …

でIP_ADAPTER_INFOのサンプルを見てみたのですが、
こちらはFREE関数を使ってメモリを最後に開放していないのですが、これはサンプルだから省略されたということでしょうか?
通常は、hohuhohuさんの書かれるとおり、最後にFREE
を入れるべきですよね?

補足日時:2005/05/01 02:24
    • good
    • 0

ちょっと修正です。


aiSizeを初期化もせずにつかっているのがまずいです。
本来この手法はOutBufLenに0を指定して、強制的にERROR_BUFFER_OVERFLOWを起こし必要な領域のサイズを得ようというもののようです(このときpAdapterInfoは問題にならないのでNULLを入れている)。
MSDNのサンプルソースではアダプタが複数あった場合にのみ発生したERROR_BUFFER_OVERFLOWを処理しているのに対し、最初からERROR_BUFFER_OVERFLOWを前提にしてプログラムを組んでいるという違いがあります。
ただpAdapterInfoにNULLを指定した場合にもOutBufLenの値に関係なくERROR_BUFFER_OVERFLOWが発生し、OutBufLenに必要な領域のサイズが帰ってきているようです。
今回のケースではこの現象により正常に動いているように見えていたわけですが、MSDNにはERROR_BUFFER_OVERFLOWの発生条件としてOutBufLenが小さすぎること以外書かれていないので、この現象に依存したプログラムは避けるべきだと思います。
    • good
    • 0
この回答へのお礼

hohuhohuさん返信有難うございます。

なるほど、確かに自分のソースは最初からERROR_BUFFER_OVERFLOWをさせて取得しています。
(初期化もせずに)

MSDNのソースに直した形での取得方法にしようと
思います。

お礼日時:2005/05/05 15:05

> これはIP_ADAPTER_INFOのポインタ型のPIP_ADAPTER_INFOを使用することでNIC分のメモリを


> 確保しているという解釈でよいでしょうか?

MSDNを見る限りそういうことだろうと判断して回答しました。
説明文を読むと十分な領域さえ確保されていれば、サイズはどのような値でもいいようです。
BYTE buf[5120];
DWORD aiSize=5120;

GetAdaptersInfo((PIP_ADAPTER_INFO)buf,&aiSize);
でもほとんどの環境で正常に動作すると思います。


それより改めて見直してみて気になったのは、
GetAdaptersInfo(NULL,&aiSize); //サイズ取得
ですね。
確かに必要な容量がaiSizeに帰ってきていますが、この挙動自体はMSDNに記載されていないようです。
If this size is insufficient to hold the adapter information, GetAdaptersInfo fills in this variable with the required size, and returns an error code of ERROR_BUFFER_OVERFLOW
とはありますが、これはpOutBufLenで指定された値が必要な容量未満だったときですし。
この方法でサイズ取得するのはよく行われているようですが、記載が無い以上避けておいたほうがいいように思います。

この回答への補足

hofuhofuさん、返信ありがとうございます。

>それより改めて見直してみて気になったのは、
>GetAdaptersInfo(NULL,&aiSize); //サイズ取得
>ですね。
>確かに必要な容量がaiSizeに帰ってきていますが、
>この挙動自体はMSDNに記載されていないようです。

MSDNのサンプルを見てみたのですが、

pAdapterInfo = (IP_ADAPTER_INFO *) malloc( sizeof(IP_ADAPTER_INFO) );
ulOutBufLen = sizeof(IP_ADAPTER_INFO);

if (GetAdaptersInfo( pAdapterInfo, &ulOutBufLen) != ERROR_SUCCESS) {
GlobalFree (pAdapterInfo);
pAdapterInfo = (IP_ADAPTER_INFO *) malloc (ulOutBufLen);
}

この記述をみると、最初は、
IP_ADAPTER_INFO一つ分で確保しに行ってますが、
そのとき、if文で
GetAdaptersInfo( pAdapterInfo, &ulOutBufLen)
をして、失敗だったらulOutBufLenを使用して
再度所得しなおしているので、MSDN上いちおう
問題ないのではないでしょうか?

補足日時:2005/05/02 01:01
    • good
    • 0

>こちらはFREE関数を使ってメモリを最後に開放していないのですが、これはサンプルだから省略されたということでしょうか?


>通常は、hohuhohuさんの書かれるとおり、最後にFREE
を入れるべきですよね?

当たり前のことですが、free()を呼ぶのはその領域が不要になったとき。
MSDNのサンプル、関数にはなってないですよね。

取得したMACアドレス、printfで表示するだけでしたらすぐにfreeしてもいいですけど、他にも使うんでしたら解放しちゃまずいですよね。
    • good
    • 0
この回答へのお礼

taka_tetsuさん返信ありがとうございます。

>当たり前のことですが、free()を呼ぶのはその領域
>が不要になったとき。
>MSDNのサンプル、関数にはなってないですよね。

>取得したMACアドレス、printfで表示するだけでし
>たらすぐにfreeしてもいいですけど、他にも使うん
>でしたら解放しちゃまずいですよね。

なるほど、確かに関数になっていませんでした。
プログラムも理解することができました。
ありがとうございました。

お礼日時:2005/05/02 00:49

>実際、自分のプログラム(雑誌に載っていたサンプル)


>だとなぜエラーなのか原因がわからなかったのです。

書かれているコード、質問に書かれた部分で全部ですか?
使用してる変数の宣言からAPIの呼び出しまでの間を全部書いていただければどこがおかしいか確認できると思いますけど。

>ERROR_INVALID_PARAMETERについても英語で説明
>はありますが、、いまいち対処法をみいだすことが
>できなくて。

ERROR_INVALID_PARAMETERは、「パラメータが間違ってます」ってだけなんで、使い方が違うとしか言いようが無いです。
    • good
    • 0

MSDNにサンプルつきで書いてありますけど。



http://msdn.microsoft.com/library/default.asp?ur …
    • good
    • 0
この回答へのお礼

taka_tetsuさん、返信ありがとうございます。

実は、自分も調べていて紹介していただいたURL
にはいったのですが、

実際、自分のプログラム(雑誌に載っていたサンプル)
だとなぜエラーなのか原因がわからなかったのです。

ERROR_INVALID_PARAMETERについても英語で説明
はありますが、、いまいち対処法をみいだすことが
できなくて。

他にも、色々と調べてはみたのですが、
ERROR_INVALID_PARAMETER
が出力されてしまっている状態です。

お礼日時:2005/04/30 15:04

お探しのQ&Aが見つからない時は、教えて!gooで質問しましょう!