65.9K
CodeProject 正在变化。 阅读更多。
Home

SENS 网络事件组件的实现和订阅

starIconstarIconstarIconstarIcon
emptyStarIcon
starIcon

4.58/5 (11投票s)

2006年5月24日

Ms-PL

4分钟阅读

viewsIcon

48608

downloadIcon

250

如何使用 SENS 网络事件组件检测网络连接。

引言

本教程将帮助您了解 SENS 组件。您将开发一个应用程序,用于计算您在网上冲浪期间的连接时间。本教程分为三个部分。在第一部分中,我们将探讨 SENS 组件在检测网络连接方面的用途。在第二部分中,我们将学习如何通过系统托盘访问您的应用程序。最后,我们将提供有关如何保存/存储数据和统计信息的信息。

第一部分

好了,开始创建一个名为 ConnectionTimer 的 Windows 应用程序项目。

好的,现在我们必须为“SENS 事件类型库”组件添加一个引用,但这还不足以利用 SENS 提供的服务。SENS(系统事件通知服务)检测网络连接中的事件,但当我们使用 COM 组件的事件通知时,我们必须订阅它才能使用它。因此,我们还必须添加“COM+ 1.0 管理类型库”组件进行订阅。(要添加引用,请在解决方案资源管理器中右键单击“引用”节点,然后选择“添加引用...”。)

Visual Studio 会自动导入组件使用所需的接口类;看一眼吧。

此时,我们可以使用 ISensNetwork 接口。为此,我们必须为每个事件通知订阅我们特定应用程序所需的服务。为此,我们将使用 COMAdmin 组件。订阅发生在我们要使用的每个事件上。因此,请查看如何订阅事件,并创建一个函数来实现这一点!

// add the package
using COMAdmin;
...
// add the member variable for the subscription
COMAdminCatalogClass comAdmin = new COMAdminCatalogClass();
ICatalogCollection subCollection;
...
// each event need subscription, make a function that we can re-call
private void SubscribeToEvent(ICatalogCollection 
             subCollection, string methodName)
{
    // new subscription
    ICatalogObject catalogObject = 
             (ICatalogObject) subCollection.Add();
    // we must insert the CLSID of our component, we can see in the 
    // Component Services Tool or in the registry editor
    catalogObject.set_Value("EventCLSID", 
             "{D5978620-5B9F-11D1-8DD2-00AA004ABD5E}");
    catalogObject.set_Value("Name", 
             "Subscription to " + methodName + " event");
    // the method name
    catalogObject.set_Value("MethodName", methodName);
    // who subscribe the event
    catalogObject.set_Value("SubscriberInterface", this);
    catalogObject.set_Value("Enabled", true);
    catalogObject.set_Value("PerUser", true);
    subCollection.SaveChanges();
}

现在,我们必须使用 ISensNetwork 接口。它是一个接口,因此我们必须从 Form 类扩展我们的类,并实现 ISensNetwork 接口及其所有方法!

// extend our class with the ISensNetwork interface
public sealed class Form1 : System.Windows.Forms.Form, 
                            SensEvents.ISensNetwork
...
// in the construction class subscribe
// the event by use the function that we have
// precedently implement
public Form1()
{
    InitializeComponent();
    subCollection = (ICatalogCollection)
                     comAdmin.GetCollection("TransientSubscriptions");
    SubscribeToEvent(subCollection, "ConnectionMade");
    SubscribeToEvent(subCollection, "ConnectionLost");
    SubscribeToEvent(subCollection, "ConnectionMadeNoQOCInfo");
    SubscribeToEvent(subCollection, "DestinationReachable");
    SubscribeToEvent(subCollection, "DestinationReachableNoQOCInfo");
}
...
// re-implement the event of interest;
// I write all function, but the function that
// we are interest are only ConnectionLost, ConnectionMade
public void ConnectionLost(string s, uint u)
{
    MessageBox.Show("ConnectionLost");
}
public void ConnectionMade(string s, uint u, 
            ref SensEvents.SENS_QOCINFO info)
{
    MessageBox.Show("ConnectionMade");
}
public void ConnectionMadeNoQOCInfo(string s, uint u)
{
    MessageBox.Show("ConnectionMadeNoQOCInfo");
}
public void DestinationReachable(string s0, string s, 
            uint u, ref SensEvents.SENS_QOCINFO info)
{
    MessageBox.Show("DestinationReachable");
}
public void DestinationReachableNoQOCInfo(string s0, 
                                   string s, uint u)
{
    MessageBox.Show("DestinationReachableNoQOCInfo");
}

好了,我们的程序已经准备好开始检测网络连接了!

第二部分

现在我们来讨论如何为我们的应用程序提供更好的界面。例如,将应用程序发送到 Windows 系统托盘,并在连接或断开连接时更改图标(比经典的 MessageBox 更好)会很有趣。但首先,添加一个 ContextMenu(如下图所示),以便在应用程序隐藏在系统托盘中时进行访问。

好了,最适合做这个的类是 NotifyIcon。以图形方式添加它,并设置其参数。

Text = "Connection Timer - not Connected"
ContextMenu = contextMenu1
// the icon to display... I chose to visualize the application icon
Icon = App.ico

在代码视图中,添加以下代码:

// in the load event of the form add
// the code needed to hide the form at the startup
this.WindowState = FormWindowState.Minimized;
this.Visible = false;
this.ShowInTaskbar = false;

应用程序图标显示未连接。对于连接的图标,我复制了 app.ico 并将其重命名为 Disconnected.ico,然后将其填充为红色。我们现在必须编写代码在运行时更改图标,但首先请记住将图标嵌入到应用程序项目中。选择图标,转到“属性”,并将“生成操作”设置为“嵌入式资源”。现在,修改之前的代码:

public void ConnectionLost(string s, uint u)
{
    this.notifyIcon1.Text = "Connection Timer - not Connected";
    this.notifyIcon1.Icon = new Icon(GetType(), "App.ico");
    //MessageBox.Show("ConnectionLost");
}
public void ConnectionMade(string s, uint u, 
            ref SensEvents.SENS_QOCINFO info)
{
    this.notifyIcon1.Text = "Connection Timer - Connected";
    this.notifyIcon1.Icon = new Icon(GetType(), "Disconnected.ico");
    //MessageBox.Show("ConnectionMade");
}

我建议注释掉其他方法,如果您不使用它们的话。好了,现在我们必须在菜单事件中插入代码……双击菜单项的每个事件选项,并在函数中编辑代码。

// add the event for the menu item and implement it
private void restoreStat_Click(object sender, System.EventArgs e)
{
    this.WindowState = FormWindowState.Normal;
    this.ShowInTaskbar = true;
}

private void exitMenu_Click(object sender, System.EventArgs e)
{
    this.Close();
}

好了……如果您想尝试该应用程序,可以在系统托盘中看到它,并带有新图标。

第三部分

好了,本教程的最后一部分是关于数据如何保存和恢复,以及对我们连接相关信息进行简单的统计。我选择使用 XML 文件来保存数据。我们保存的信息是连接和断开连接的日期和时间。首先,创建(如果不存在)XML 文件来注册代表我们连接的记录。创建一个函数并在 Form1 构造函数中调用它。

using System.IO;
...
System.Data.DataSet dts;
...
public Form1()
{
    InitializeComponent();
    subCollection = (ICatalogCollection)
      comAdmin.GetCollection("TransientSubscriptions");
    SubscribeToEvent(subCollection, "ConnectionMade");
    SubscribeToEvent(subCollection, "ConnectionLost");
    //SubscribeToEvent(subCollection, "ConnectionMadeNoQOCInfo");
    //SubscribeToEvent(subCollection, "DestinationReachable");
    //SubscribeToEvent(subCollection, "DestinationReachableNoQOCInfo");
    CheckFile();
}
...
public void CheckFile()
{
    FileInfo TheFile = new FileInfo(@"fileData.xml");
    dts = new DataSet();
    if (!TheFile.Exists)
    {
        System.Data.DataTable dtt = dts.Tables.Add();
        dtt.Columns.Add("fromDate", System.Type.GetType("System.DateTime"));
        dtt.Columns.Add("toDate", System.Type.GetType("System.DateTime"));

        dts.WriteXml(@"fileData.xml", System.Data.XmlWriteMode.WriteSchema);
    }
    else
    {
        dts.ReadXml(@"fileData.xml");
    }
}

现在,添加代码以在建立连接和丢失连接时生成 DataSetDataTable 的新行。

public void ConnectionLost(string s, uint u)
{
    this.notifyIcon1.Text = "Connection Timer - not Connected";
    this.notifyIcon1.Icon = new Icon(GetType(), "App.ico");
    //MessageBox.Show("ConnectionLost");
    // here the code to modify the last row inserted by the ConnectionMade function
    dts.Tables[0].Rows[dts.Tables[0].Rows.Count-1]["toDate"] = System.DateTime.Now;
    dts.WriteXml(@"fileData.xml", System.Data.XmlWriteMode.WriteSchema);
}
public void ConnectionMade(string s, uint u, ref SensEvents.SENS_QOCINFO info)
{
    this.notifyIcon1.Text = "Connection Timer - Connected";
    this.notifyIcon1.Icon = new Icon(GetType(), "Disconnected.ico");
    //MessageBox.Show("ConnectionMade");
    // here the code to add a new record when the connection is made
    System.Data.DataRow dtr = dts.Tables[0].NewRow();
    dtr["fromDate"] = System.DateTime.Now;
    dts.Tables[0].Rows.Add(dtr);
    dts.WriteXml(@"fileData.xml", System.Data.XmlWriteMode.WriteSchema);
}

好了,此时,我们只需要添加一些控件来处理数据并生成一些关于 XML 中连接记录的简单统计信息。我把这个留给您自己去享受!

结论

这是我的第一个教程。我经常关注这个网站,并且发现能够在我遇到困难时依靠许多像我一样的开发者的帮助非常有益。我希望通过写这个教程来帮助到别人。我想强调的是,该应用程序并非为防错而开发,代码可以写得更健壮、更线性,但这个教程的特别之处在于组件与事件的订阅,这是我发现自己很难做到的!此代码没有考虑同时连接多个网络,XML 文件可以包含更多信息,可以以其他更安全的方式保存。NotifyIcon 类在框架的 2.0 版本中具有更多功能,它可以利用气球消息与用户进行通信。不过……我仍然希望您觉得这篇文章很有趣!特别感谢我的美国朋友,他纠正了我基本的英语错误,并总是和我下棋!

感谢您的关注!

© . All rights reserved.