c#-4.0 - triunviratos - triunviro
C#4, interoperabilidad COM y UPnP: un triunvirato que intenta (2)
Parece que pude hacer que funcione. Dos opciones: con una interfaz personalizada "INATNumberOfEntriesCallback" (que no parece estar declarada en la biblioteca de tipos por cierto, debe declararla usted mismo) y utilizando el envío simple con DispId (0). La conversión a IDispatch / IUnknown se realiza automáticamente por el marco. Asi que:
Opción 1.
Declare INATNumberOfEntriesCallback y cree una clase de devolución de llamada que implemente esa interfaz (la parte difícil es Guid: proviene del archivo "Natupnp.h" y no parece estar en la biblioteca de tipos).
// 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");
}
}
Opcion 2.
Use despacho simple. La documentación dice que puede usar dispid (0) y debe llamarse, con 4 (!) Parámetros (consulte la sección de comentarios en documentos ). Entonces, básicamente, la siguiente construcción parece funcionar de manera "expeditiva":
[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");
}
}
Estoy tratando de escribir un poco de código (solo para uso doméstico) que usa UPnP para NAT transversal, usando C # 4 y la API transversal NAT basada en COM de Microsoft (Hnetcfg.dll).
Desafortunadamente (o quizás afortunadamente) la última vez que tuve que hacer una interoperabilidad COM en .NET fue en algún momento alrededor de la última edad de hielo, y me parece fundamentalmente confundido sobre el uso de tipos dinámicos de C # para la interoperabilidad y cómo escribir una devolución de llamada (para que el servidor COM llama a mi código administrado).
Aquí hay unas pocas líneas de código emocionantes:
// 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");
}
}
En el código anterior, las llamadas Agregar y Eliminar funcionan absolutamente bien. Estupendo.
El problema es que también me gustaría saber cuándo ha cambiado la cantidad de entradas de asignación de puertos, y para hacerlo necesito registrar una interfaz de devolución de llamada ( INATEventManager :: put_NumberOfEntriesCallback ), que debe admitir las interfaces INATNumberOfEntriesCallback o IDispatch. El buscador de objetos de VS2012 describe INATEventManager :: put_NumberOfEntriesCallback así:
dynamic NumberOfEntriesCallback { set; }
Correcto, así que tenía la impresión de que en C # 4 no debería decorar nada con atributos sofisticados y que puedo registrar mi devolución de llamada simplemente colocando a un delegado en INATEventManager :: put_NumberOfEntriesCallback de una manera vulgar y dejando que .NET se preocupe sobre IDispatch y aclarar el desorden; pero parece que estoy terriblemente equivocado.
Entonces, eh ... ¿Qué debo hacer para asegurar que se llame a mi método NewNumberOfEntries?
También me preocupa un poco que pueda escribir nat.NATEventManager.NumberOfEntriesCallback = 1;
o nat.NATEventManager.NumberOfEntriesCallback = "Sausages";
sin una excepción lanzada.
Tuve el mismo problema que tenía, y como no hay mucha ayuda sobre el tema, ¡su publicación ayudó muchísimo! No me dejaría comentar tu respuesta porque no tengo suficientes puntos o lo que sea, pero tu respuesta es la mejor, pero no funciona como pensé.
nat.NATEventManager.ExternalIPAddressCallback = new CallbackDisp();
Funciona, utilizando el mismo despacho, y le dirá cuándo cambia la IP externa. SIN EMBARGO,
nat.NATEventManager.NumberOfEntriesCallback = new CallbackDisp();
solo informa cambios en el mapa UPnP de estas condiciones: A.) Fue agregado / eliminado por la instancia de NATUPnP. En este caso:
nat.StaticPortMappingCollection.Add();
O B.) ya estaba mapeado cuando se creó la instancia:
var nat = new UPnPNAT();
Como ejemplo, si Utorrent se estaba ejecutando cuando comenzó su programa y usted tenía algo para bloquear el programa de salir (Console.WriteLine ();), por ejemplo .. Cuando salga de Utorrent la devolución de llamada se disparará, y le notificará de la cambios en el mapa Que es exactamente lo que quería en primer lugar. Sin embargo, si vuelve a abrir Utorrent, o cualquier otra aplicación que use UPnP, NO activará la devolución de llamada, y no le notificará del cambio.
Huelga decir que ha sido muy frustrante. Si lo resuelves, comparte! Sé que puedo implementar fácilmente la funcionalidad al sondear StaticPortMappingCollection en un intervalo determinado, pero me parece un poco ''hacky''.