NICのデバイス名とインデックスの列挙 (C#)(F#)
NICのデバイス名とインデックス番号は、通常、表面上はプログラムに現れて来ませんが、ネットワーク関連のプログラムを作成していると、要求されることがよくあります。
この情報は、iphlpapi.dllのGetInterfaceInfo()を使用することで取得できます。
GetInterfaceInfo()の返すデータサイズがインターフェースの数により変化し、不定なため、通常、バッファにnullを設定して、強制的にエラーを発生させ、必要なバッファサイズを取得してから使用します。
C#サンプル
using System; using System.Runtime.InteropServices; namespace Example { class Program { [DllImport("iphlpapi", CharSet = CharSet.Auto)] extern static int GetInterfaceInfo(Byte[] pIfTable, ref int pOutBufLen); const int MAX_ADAPTER_NAME = 128; const int ERROR_INSUFFICIENT_BUFFER = 122; const int ERROR_SUCCESS = 0; [StructLayout(LayoutKind.Sequential, CharSet = CharSet.Auto)] struct IP_ADAPTER_INDEX_MAP { public int Index; [MarshalAs(UnmanagedType.ByValTStr, SizeConst = MAX_ADAPTER_NAME)] public String Name; } //IP_ADAPTER_INDEX_MAPのサイズ取得 static int SizeOfMap() { IP_ADAPTER_INDEX_MAP map = new IP_ADAPTER_INDEX_MAP(); return Marshal.SizeOf(map); } //byte[]から IP_ADAPTER_INDEX_MAP構造体へのデータコピー static IP_ADAPTER_INDEX_MAP CreateIpAdapterIndexMax(byte[] buffer, int offset) { IntPtr ptr = Marshal.AllocHGlobal(SizeOfMap()); Marshal.Copy(buffer, offset, ptr, SizeOfMap()); IP_ADAPTER_INDEX_MAP map = (IP_ADAPTER_INDEX_MAP)Marshal.PtrToStructure(ptr, typeof(IP_ADAPTER_INDEX_MAP)); Marshal.FreeHGlobal(ptr); return map; } static void Main(string[] args) { int size = 0; if (GetInterfaceInfo(null, ref size) == ERROR_INSUFFICIENT_BUFFER) {//nullを設定して必要サイズを得る Byte[] buffer = new Byte[size];//必要サイズを確保 if (GetInterfaceInfo(buffer, ref size) == ERROR_SUCCESS) {//バッファをセットして2回目の呼び出し int offSet = 0; int num = BitConverter.ToInt32(buffer, offSet);//IP_ADAPTER_INDEX_MAP配列の数を取得 offSet += Marshal.SizeOf(num); for (int i = 0; i < num; i++) {//インターフェース数分だけ処理する IP_ADAPTER_INDEX_MAP map = CreateIpAdapterIndexMax(buffer, offSet); Console.WriteLine(string.Format("nindex:{0}", map.Index)); Console.WriteLine(string.Format("Name:{0}", map.Name)); offSet += SizeOfMap(); } } } Console.WriteLine("何かのキーを押してください。"); Console.ReadKey(); } } }
F#サンプル
open System open System.Runtime.InteropServices [<DllImport("iphlpapi")>] extern int GetInterfaceInfo(Byte[] pIfTable,int *pOutBufLen) let MAX_ADAPTER_NAME = 128 let ERROR_INSUFFICIENT_BUFFER = 122 let ERROR_SUCCESS = 0 [<StructLayout(LayoutKind.Sequential,CharSet=CharSet.Auto)>] type IP_ADAPTER_INDEX_MAP = struct val Index : int [<MarshalAs(UnmanagedType.ByValTStr, SizeConst=128)>] val Name : string end //IP_ADAPTER_INDEX_MAPのサイズ取得 let SizeOfMap() = let map = new IP_ADAPTER_INDEX_MAP() Marshal.SizeOf(map) //byte[]から IP_ADAPTER_INDEX_MAP構造体へのデータコピー let CreateIpAdapterIndexMax(buffer:byte[],offset:int) = let ptr = Marshal.AllocHGlobal(SizeOfMap()) Marshal.Copy(buffer, offset, ptr,SizeOfMap()) let map = Marshal.PtrToStructure(ptr, typeof<IP_ADAPTER_INDEX_MAP>):?>IP_ADAPTER_INDEX_MAP Marshal.FreeHGlobal(ptr) map let mutable size = 0; if GetInterfaceInfo(null, &&size) = ERROR_INSUFFICIENT_BUFFER then //nullを設定して必要サイズを得る let buffer : byte array = Array.create size 0uy //必要サイズを確保 if GetInterfaceInfo(buffer, &&size) = ERROR_SUCCESS then //バッファをセットして2回目の呼び出し let num = BitConverter.ToInt32(buffer,0);//IP_ADAPTER_INDEX_MAP配列の数を取得 let mutable offSet= Marshal.SizeOf(num) for i in 1 .. num do //インターフェース数分だけ処理する let map = CreateIpAdapterIndexMax(buffer, offSet) printfn "nindex:%d" map.Index printfn "Name:%s" map.Name offSet <- offSet + SizeOfMap() printfn "何かのキーを押してください。" Console.ReadKey() |> ignore