C# 4 と Microsoft の COM ベースのNAT トラバーサル API (Hnetcfg.dll)を使用して、NAT トラバーサルに UPnP を使用するコード (家庭用のみ) を少し書こうとしています。
残念なことに (またはおそらく幸いなことに)、最後に .NET で COM 相互運用を行う必要があったのは、最後の氷河期の頃でした。相互運用のための C# の動的型の使用とコールバックの記述方法について根本的に混乱しているようです (そのため、 COM サーバーがマネージ コードを呼び出します)。
エキサイティングな数行のコードを次に示します。
// Referencing COM NATUPNPLib ("NATUPnP 1.0 Type Library")
using System;
using NATUPNPLib;
class NATUPnPExample
{
public delegate void NewNumberOfEntriesDelegate(int lNewNumberOfEntries);
public static void NewNumberOfEntries(int lNewNumberOfEntries)
{
Console.WriteLine("New number of entries: {0}", lNewNumberOfEntries);
}
public static void Main(string[] args)
{
UPnPNAT nat = new UPnPNAT();
NewNumberOfEntriesDelegate numberOfEntriesCallback = NewNumberOfEntries;
nat.NATEventManager.NumberOfEntriesCallback = numberOfEntriesCallback;
nat.StaticPortMappingCollection.Add(4555, "TCP", 4555, "192.168.0.1", true, "UPnPNAT Test");
// Presumably my NewNumberOfEntries() method should be called by the COM component about now
nat.StaticPortMappingCollection.Remove(4555, "TCP");
}
}
上記のコードでは、Add と Remove の呼び出しは問題なく機能します。素晴らしい。
問題は、ポート マッピング エントリの数がいつ変更されたかを知りたいことです。そのためには、コールバック インターフェイス ( INATEventManager::put_NumberOfEntriesCallback ) を登録する必要があります。これは、 INATNumberOfEntriesCallback または IDispatch インターフェイスをサポートする必要があります。VS2012 のオブジェクト ブラウザは、 INATEventManager::put_NumberOfEntriesCallback を次のように記述します。
dynamic NumberOfEntriesCallback { set; }
C# 4 では派手な属性で何かを装飾する必要はなく、下品な方法でデリゲートを INATEventManager::put_NumberOfEntriesCallback に詰め込み、.NET を心配させるだけでコールバックを登録できるという印象を受けました。 IDispatch について、混乱を解消します。しかし、私はひどく間違っているようです。
それで、ええと... NewNumberOfEntries メソッドが確実に呼び出されるようにするにはどうすればよいですか?
また、例外がスローされずに記述できるnat.NATEventManager.NumberOfEntriesCallback = 1;
かどうかも少し心配です。nat.NATEventManager.NumberOfEntriesCallback = "Sausages";