Loo*_*ofy 11 com upnp idispatch c#-4.0
我正在尝试编写一些使用UPnP进行NAT遍历的代码(仅供家庭使用),使用C#4和Microsoft的基于COM的NAT遍历API(Hnetcfg.dll).
不幸的是(或者幸运的是)我最后一次在.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");
}
}
Run Code Online (Sandbox Code Playgroud)
在上面的代码中,添加和删除调用工作绝对正常.了不起.
麻烦的是,我还想知道端口映射条目的数量何时发生了变化,为此我需要注册一个回调接口(INATEventManager :: put_NumberOfEntriesCallback),它必须支持INATNumberOfEntriesCallback或IDispatch接口.VS2012的对象浏览器因此描述了INATEventManager :: put_NumberOfEntriesCallback:
dynamic NumberOfEntriesCallback { set; }
Run Code Online (Sandbox Code Playgroud)
是的,所以我的印象是在C#4中我不应该用花哨的属性来装饰任何东西,并且我可以简单地通过以粗俗的方式将一个委托插入INATEventManager :: put_NumberOfEntriesCallback来注册我的回调并让.NET担心关于IDispatch并清理混乱; 但似乎我非常错误.
所以,呃......我该怎么做才能确保我的NewNumberOfEntries方法被调用?
我也有点担心我可以写nat.NATEventManager.NumberOfEntriesCallback = 1;或nat.NATEventManager.NumberOfEntriesCallback = "Sausages";没有抛出异常.
看来我能够让它发挥作用。有两个选项 - 使用自定义接口“INATNumberOfEntriesCallback”(顺便说一句,它似乎没有在类型库中声明,您需要自己声明)和使用带有 DispId(0) 的普通调度。到 IDispatch/IUnknown 的转换由框架自动执行。所以:
选项1。
声明 INATNumberOfEntriesCallback 并创建一个实现该接口的回调类(棘手的部分是 Guid - 它来自“Natupnp.h”文件,并且似乎不在类型库中)。
// declare INATNumberOfEntriesCallback interface
[ComVisible(true)]
[Guid("C83A0A74-91EE-41B6-B67A-67E0F00BBD78")]
[InterfaceType(ComInterfaceType.InterfaceIsIUnknown)]
public interface INATNumberOfEntriesCallback
{
void NewNumberOfEntries(int val);
};
// implement callback object
[ComVisible(true)]
[ClassInterface(ClassInterfaceType.None)]
public class CallbackNewNumberOfEntries : INATNumberOfEntriesCallback
{
public void NewNumberOfEntries(int val)
{
Console.WriteLine("Number of entries changed: {0}", val);
}
}
class NATUPnPExample
{
public static void Main(string[] args)
{
var nat = new UPnPNAT();
nat.NATEventManager.NumberOfEntriesCallback = new CallbackNewNumberOfEntries();
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");
}
}
Run Code Online (Sandbox Code Playgroud)
选项 2。
使用普通调度。文档说您可以使用 dispid(0) 并且应该使用 4 个(!)参数来调用它(请参阅文档中的备注部分)。所以基本上以下构造似乎以“调度”方式工作:
[ComVisible(true)]
[ClassInterface(ClassInterfaceType.AutoDispatch)]
public class CallbackDisp
{
[DispId(0)]
public void OnChange(string updateType, object obj, object name, object val)
{
Console.WriteLine("{0}: {1} = {2}", updateType, name, val);
}
}
class NATUPnPExample
{
public static void Main(string[] args)
{
var nat = new UPnPNAT();
nat.NATEventManager.NumberOfEntriesCallback = new CallbackDisp();
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");
}
}
Run Code Online (Sandbox Code Playgroud)
| 归档时间: |
|
| 查看次数: |
519 次 |
| 最近记录: |