DHCPで取得したアドレスのreleaseとrenew (C#)(F#)
2011.11.28 追記
本記事の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#サンプル
まったくひどいサンプルになってます。
本当は、
[<DllImport("Iphlpapi.dll", CharSet = CharSet.Auto)>] extern int IpReleaseAddress(IP_ADAPTER_INDEX_MAP * AdapterInfo)
としたかったのですが、「ジェネリックコンストラクターの型’IP_ADAPTER_INDEX_MAP’は、アンマネージ型にする必要があります」っと言って受け付けてくれません。
IP_ADAPTER_INDEX_MAPにStringが無ければ問題無いようなのですが・・・・
結局、パラメータを(IntPtr AdapterInfo)として宣言したので、非常にひどい状態になってしまってます。
#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 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 num = Marshal.ReadInt32(p)//IP_INTERFACE_INFO.NumAdapters(データ数) let ptr = IntPtr.Add(p, 4) let ar = let step = Marshal.SizeOf(typeof<IP_ADAPTER_INDEX_MAP>) [0..num-1] |>List.map(fun i ->IntPtr.Add(ptr, step * i)) //データへのポインタ |>List.map(fun p -> Marshal.PtrToStructure(p,typeof<IP_ADAPTER_INDEX_MAP>):?>IP_ADAPTER_INDEX_MAP) Marshal.Release(p)|>ignore ar else [] else [] ar|>Seq.iter(fun a -> printfn "%d %s" a.Index a.Name) let ptr = Marshal.AllocHGlobal(Marshal.SizeOf(typeof<IP_ADAPTER_INDEX_MAP>)) //release printfn "n何かのキーを押すと、IPアドレスをreleaseします。" Console.ReadKey() |> ignore ar|>Seq.iter(fun a -> Marshal.StructureToPtr(a, ptr, false) IpReleaseAddress(ptr)|>ignore ) printfn "releaseしました。" //renew printfn "n何かのキーを押すと、IPアドレスをrenewします。" Console.ReadKey() |> ignore ar|>Seq.iter(fun a -> Marshal.StructureToPtr(a, ptr, false) IpRenewAddress(ptr)|>ignore ) printfn "renewしました。" Marshal.FreeHGlobal(ptr) printfn "" printfn "何かのキーを押してください。" Console.ReadKey() |> ignore