.NET Visual C#を使ってルータからグローバルIPアドレスを取得する方法です。
開発環境は、以下の通りです。
- IDE : Microsoft Visual Studio 2010(以下VS2010)
- OS : Windows 7
- 言語 : C# (4.0)
参照の追加
通常通りC#のプロジェクトを作成し、「UPNPLib」への参照を追加します。
メニューの「プロジェクト」から「参照の追加」を選択し、「COM」タブのリストから「UPnP 1.0 Type Library (Control Point)」を選択して「OK」ボタンを押せば完了です。
コード
kamoya11さんのコードがものすごく参考になりました。
C#でUPnP NAT Traversal - kamoyaの日記
このコードは、ポート開放処理に対応したものなので、コードの追記が必要でした。また、VS2010で一部エラーになってしまう部分があったので、適宜修正が必要です。
以下が修正したコードです。
using System;
using System.Runtime.InteropServices;
using UPNPLib;
class UPnPControlPoint
{
private UPnPService Service { get; set; }
private UPnPDevice GetDevice(IUPnPDeviceFinder finder, string typeUri)
{
foreach (UPnPDevice item in finder.FindByType(typeUri, 0))
{
return item;
}
return null;
}
private UPnPDevice GetDevice(IUPnPDeviceFinder finder)
{
UPnPDevice device = this.GetDevice(finder, "urn:schemas-upnp-org:service:WANPPPConnection:1");
if (device == null)
{
device = this.GetDevice(finder, "urn:schemas-upnp-org:service:WANIPConnection:1");
}
return device;
}
private UPnPService GetService(UPnPDevice device, string serviceId)
{
try
{
return device.Services[serviceId];
}
catch (ArgumentException)
{
return null;
}
}
private UPnPService GetService(UPnPDevice device)
{
UPnPService service = this.GetService(device, "urn:upnp-org:serviceId:WANPPPConn1");
if (service == null)
{
service = this.GetService(device, "urn:upnp-org:serviceId:WANIPConn1");
}
return service;
}
private UPnPService GetService()
{
UPnPDevice device = this.GetDevice(new UPnPDeviceFinder());
if (device == null)
{
return null;
}
return this.GetService(device);
}
public UPnPControlPoint()
{
this.Service = GetService();
}
private object InvokeAction(string bstrActionName, object vInActionArgs)
{
if (Service == null)
{
return null;
}
try
{
object result = new object();
Service.InvokeAction(bstrActionName, vInActionArgs, ref result);
return result;
}
catch (COMException)
{
return null;
}
}
public string GetExternalIPAddress()
{
object result = InvokeAction("GetExternalIPAddress", new object[] { });
if (result == null)
{
return null;
}
return (string)((object[])result)[0];
}
public void AddPortMapping(string remoteHost, ushort externalPort, string protocol, ushort internalPort, string internalClient, string description)
{
var arguments = new object[] { remoteHost, externalPort, protocol, internalPort, internalClient, true, description, 0 };
InvokeAction("AddPortMapping", arguments);
}
public void DeletePortMapping(string remoteHost, ushort externalPort, string protocol)
{
var arguments = new object[] { remoteHost, externalPort, protocol };
InvokeAction("DeletePortMapping", arguments);
}
}
赤字の部分が変更と追記した部分になります。
このクラスを使う場合は、以下のようにコーディングします。
private void button1_Click(object sender, EventArgs e)
{
new Task(() =>
{
UPnPControlPoint p = new UPnPControlPoint();
var result = p.GetExternalIPAddress();
this.Invoke((MethodInvoker)delegate()
{
this.textBox1.Text = result;
});
}).Start();
}
グローバルIPアドレスを取得する時に、約15秒ほど時間がかかる為、「Task」を利用して非同期処理を行っています。
フォームと同じスレッドで実行すると、フリーズしてしまうので注意が必要です。