DHCPで取得したアドレスのreleaseとrenew (C#)(F#) その2
先日の同タイトルの記事のうち、F#サンプルを書き直してみたので再投です。
DHCPで取得した動的アドレスは、iphelapi.dllのIpReleaseAddressとIpRenewAddressで開放と再取得が可能です。同APIのパラメータ(IP_ADAPTER_INDEX_MAP )は、GetInterfaceInfoで取得したインターフェース情報をそのまま渡します。
C#サンプル
using System; using System.Runtime.InteropServices; using System.Collections.Generic; namespace Examlpe { class Program { const int MAX_ADAPTER_NAME = 128; const int ERROR_INSUFFICIENT_BUFFER = 122; const int ERROR_SUCCESS = 0; [DllImport("Iphlpapi.dll", CharSet = CharSet.Auto)] static extern int IpReleaseAddress(ref IP_ADAPTER_INDEX_MAP AdapterInfo); [DllImport("Iphlpapi.dll", CharSet = CharSet.Auto)] static extern int IpRenewAddress(ref IP_ADAPTER_INDEX_MAP AdapterInfo); [DllImport("Iphlpapi.dll", CharSet = CharSet.Auto)] static extern int GetInterfaceInfo(IntPtr PIfTableBuffer, ref int size); [StructLayout(LayoutKind.Sequential, CharSet = CharSet.Auto)] struct IP_ADAPTER_INDEX_MAP { public int Index; [MarshalAs(UnmanagedType.ByValTStr, SizeConst = MAX_ADAPTER_NAME)] public String Name; } static void Main(string[] args) { var ar = new List<IP_ADAPTER_INDEX_MAP>(); int size = 0; if (GetInterfaceInfo(IntPtr.Zero, ref size) == ERROR_INSUFFICIENT_BUFFER) {//nullを設定して必要サイズを得る var p = Marshal.AllocHGlobal(size);//メモリ割当て if (GetInterfaceInfo(p, ref size) == ERROR_SUCCESS) {//バッファをセットして2回目の呼び出し var num = Marshal.ReadInt32(p);//IP_ADAPTER_INDEX_MAP配列の数を取得 var ptr = IntPtr.Add(p, 4); for (int i = 0; i < num; i++) {//インターフェース数分だけ処理する var adapter = (IP_ADAPTER_INDEX_MAP)Marshal.PtrToStructure(ptr, typeof(IP_ADAPTER_INDEX_MAP)); Console.WriteLine(string.Format("[{0}]{1}", adapter.Index,adapter.Name)); ar.Add(adapter); ptr = IntPtr.Add(ptr, Marshal.SizeOf(typeof(IP_ADAPTER_INDEX_MAP)));//次のデータ } } Marshal.Release(p); } //release Console.WriteLine("n何かのキーを押すと、IPアドレスをreleaseします。"); Console.ReadKey(); ar.ForEach(n => IpReleaseAddress(ref n)); Console.WriteLine("releaseしました。"); //renew Console.WriteLine("n何かの)押すと、IPアドレスをrenewします。"); Console.ReadKey(); ar.ForEach(n => IpRenewAddress(ref n)); Console.WriteLine("renewしました。"); Console.WriteLine("n何かのキーを押してください。"); Console.ReadKey(); } } }
F#サンプル
GCを全面的に信用して?インターフェースの一覧をポインタで保持してみました。
#nowarn "9" "51" open System open System.Runtime.InteropServices [<Literal>] let MAX_ADAPTER_NAME=128 let ERROR_INSUFFICIENT_BUFFER = 122 let ERROR_SUCCESS = 0 [<Struct; StructLayout(LayoutKind.Sequential, CharSet = CharSet.Auto)>] type IP_ADAPTER_INDEX_MAP = val Index:int [<MarshalAs(UnmanagedType.ByValTStr, SizeConst = MAX_ADAPTER_NAME)>] val Name:String [<DllImport("Iphlpapi.dll", CharSet = CharSet.Auto)>] extern int IpReleaseAddress(IntPtr AdapterInfo) [<DllImport("Iphlpapi.dll", CharSet = CharSet.Auto)>] extern int IpRenewAddress(IntPtr AdapterInfo) [<DllImport("Iphlpapi.dll", CharSet = CharSet.Auto)>] extern int GetInterfaceInfo(IntPtr PIfTableBuffer,int *size) let TYPE = typeof<IP_ADAPTER_INDEX_MAP> //インターフェースの一覧取得 let ar = [ let mutable size = 0 if GetInterfaceInfo(IntPtr.Zero,&&size) = ERROR_INSUFFICIENT_BUFFER then let p = Marshal.AllocHGlobal(size)//メモリ割当て if GetInterfaceInfo(p,&&size) = ERROR_SUCCESS then let step = Marshal.SizeOf(TYPE) let num = Marshal.ReadInt32(p)//IP_INTERFACE_INFO.NumAdapters(データ数) let ptr = IntPtr.Add(p, 4) for i in [0..num-1] do let p = IntPtr.Add(ptr, step*i) //データへのポインタ yield p Marshal.Release(p)|>ignore ] //インターフェースの一覧表示 ar |>Seq.map(fun p -> Marshal.PtrToStructure(p,TYPE):?>IP_ADAPTER_INDEX_MAP) |>Seq.iter(fun n -> printfn "%d %s" n.Index n.Name) //release printfn "n何かのキーを押すと、IPアドレスをreleaseします。" Console.ReadKey() |> ignore ar|>Seq.iter(fun p -> IpReleaseAddress(p)|>ignore) printfn "releaseしました。" //renew printfn "n何かのキーを押すと、IPアドレスをrenewします。" Console.ReadKey() |> ignore ar|>Seq.iter(fun p -> IpRenewAddress(p)|>ignore) printfn "renewしました。" printfn "" printfn "何かのキーを押してください。" Console.ReadKey() |> ignore