Handling connection notification between a desktop machine and Windows CE based devices

Introduction:

There are two ways that a desktop application can get notification when a Windows CE-based device gets connected with the desktop application.

  1. Registry based notification:

Registry based notification has two predefined events, AutoStartOnConnect and AutoStartOnDisconnect, each of which has its own Registry key. We can register the command lines associated with the Registry key. Whenever the device gets connected with the desktop machine, the AutoStartOnConnect event will be triggered and all the command lines registered under this will be executed. Similarly, whenever a device gets disconnected from the desktop machine, the AutoStartOnDisconnect event will be triggered and all the command lines under the AutoStartOnDisconnect key will be executed.

      For more details, refer to this MSDN link: Registry based notification.

    2. COM based notification

It includes two interfaces, IDccMan provided by Rapi.dll, and IDccManSink implemented by the application which needs the notification. These interfaces handle connection and disconnection notification.

      For more details, refer to the following link: COM based notification.

The basic difference between these two methods is that when Registry based notification causes a program to run, we cannot get notifications in the application, whereas in COM based notification, you have control on the Connection Manager, registering and deregistering for connection notification, or any kind of operation that can be best handled by the application. In this article, our focus will be on COM based notification, which is better.

Background:

There exists very few articles on Smart Device connection notifications in .NET, especially in VB.NET. We wanted to get notifications when a desktop machine is connected with a Windows CE - based device. We could not find code in VB.NET, and finally decided to write it ourselves. We used COM based notifications for getting the Connection and Disconnection events.

Using the Code:

Open the clsIDccMan.vb file in the code window. The file consists of the definitions of DccMan, DccManSink and the interfaces, IDccMan and IDccManSink. This file contains an import statement:

Imports System.Runtime.InteropServices

This import statement is needed to define the COM attributes. The delegates mentioned below are used to register the events which will be raised on Connection and Disconnection. The ComVisible attribute is used so that these delegates may be visible in COM.

<Serializable()> <ComVisible(True)> Public Delegate Sub ActiveHandler()

<Serializable()> <ComVisible(True)> Public Delegate Sub DisconnectHandler()

This class is used to get the instance of IDccMan. The implementation of this class exists in the ActiveSync Connection Manager. We can see that a key exists corresponding to the "499C0C20-A766-11cf-8011-00A0C90A8F78" in Registry.

<ComImport(), Guid("499C0C20-A766-11cf-8011-00A0C90A8F78")> _
Public Class DccMan
End Class

This interface is used to get all the methods available in IDccMan. With the help of the IDccMan::Advise method, we can register IDccManSink.

<ComImport(), Guid("A7B88841-A812-11cf-8011-00A0C90A8F78"), _
  InterfaceType(ComInterfaceType.InterfaceIsIUnknown)> _
Public Interface IDccMan
    Function Advise(ByVal pDccSink As IDccManSink, _
                    ByRef dwContext As Int32) As Int32
    Function Unadvise(ByVal dwContext As Int32) As Int32
    Sub ShowCommSettings()
    Sub AutoconnectEnable()
    Sub AutoconnectDisable()
    Sub ConnectNow()
    Sub DisconnectNow()
    Sub SetIconDataTransferring()
    Sub SetIconNoDataTransferring()
    Sub SetIconError()
End Interface

This interface is used to get all the methods available in the IDccManSink.

<Guid("A7B88840-A812-11cf-8011-00A0C90A8F78"), _
   InterfaceType(ComInterfaceType.InterfaceIsIUnknown)> _
Public Interface IDccManSink
    <PreserveSig()> Function OnLogIpAddr(<InAttribute()> ByVal _
                          dwIpAddr As Int32) As Int32
    <PreserveSig()> Function OnLogTerminated() As Int32
    <PreserveSig()> Function OnLogActive() As Int32
    <PreserveSig()> Function OnLogInactive() As Int32
    <PreserveSig()> Function OnLogAnswered() As Int32
    <PreserveSig()> Function OnLogListen() As Int32
    <PreserveSig()> Function OnLogDisconnection() As Int32
    <PreserveSig()> Function OnLogError() As Int32
End Interface

DccManSink is the main class. An object of this class is sent to the ActiveSync Connection Manager to get the notification on Connection / Disconnection. When the connection between the desktop computer and the device is established, the Connection Manager calls the IDccManSink::OnLogListen method. Once the remote connection services of both the desktop computer and the device respond, the Connection Manager calls the IDccManSink::OnLogAnswered method. When the Connection Manager has detected the communications interface, it calls the IDccManSink::OnLogActive method. Now, once the connection is established between the device and the Connection Manager, the Connection Manager calls the IDccManSink::OnLogIpAddr method. Finally, the IDccManSink::OnLogIpAddr method is invoked, and this completes the connection.

<Guid("C6659361-1625-4746-931C-36014B146679")> _
Public Class DccManSink
    Implements IDccManSink
    Public Event Active As ActiveHandler
    Public Event Disconnect As DisconnectHandler
    Public Function OnLogActive() As Int32 _
           Implements IDccManSink.OnLogActive
        RaiseEvent Active()
    End Function    
Public Function OnLogAnswered() As Int32 _
           Implements IDccManSink.OnLogAnswered
    End Function
    Public Function OnLogDisconnection() As Int32 _
           Implements IDccManSink.OnLogDisconnection
        RaiseEvent Disconnect()
    End Function
    Public Function OnLogError() As Int32 Implements IDccManSink.OnLogError
    End Function
    Public Function OnLogInactive() As Int32 _
           Implements IDccManSink.OnLogInactive
    End Function
    Public Function OnLogIpAddr(ByVal dwIpAddr As Int32) _
           As Int32 Implements IDccManSink.OnLogIpAddr
    End Function
    Public Function OnLogListen() As Int32 Implements IDccManSink.OnLogListen
    End Function
    Public Function OnLogTerminated() As Int32 _
           Implements IDccManSink.OnLogTerminated
    End Function
End Class

Open the RegisterIDccManSink.vb file in the code window. The file consists of two button click events, which are used to register and unregister the IDccManSink in Connection Manager. In the btnRegister button Click event (btnRegister_Click), we initialize the objects of IDccMan, IDccManSink, DccMan, and DccManSink. The methods are then registered in the events that will be executed on Connection/Disconnection. With the help of the line, objIDccMan.Advise(objDccManSink, intAdvaiceReturn), we register the object of DccManSink which implements IDccManSink. Here, we are passing the object of DccManSink and an integer type variable. This variable will be used to unregister the events.

Private Sub btnRegister_Click(ByVal sender As System.Object, _
            ByVal e As System.EventArgs) Handles btnRegister.Click
    'To create the object of DccMan class.
    'It is used to get the object of IDccMan
    'becuase we can not create the object of interface directly.
    Dim objDccMan As DccMan = New DccMan()
    'To create the object of IDccMan class.
    objIDccMan = CType(objDccMan, IDccMan)
    'To create the object of DccManSink class.
    'It is used to get the object of IDccManSink
    Dim objDccManSink As DccManSink = New DccManSink()
    'To create the object of IDccManSink
    'Dim objIDccManSink As IDccManSink = _
          CType(objDccManSink, IDccManSink)
    'To initialize the event handlers.
    AddHandler objDccManSink.Active, AddressOf OnConnection
    AddHandler objDccManSink.Disconnect, AddressOf OnDisConnection
    'To register the IDccManSink
    objIDccMan.Advise(objDccManSink, intAdvaiceReturn)
End Sub

We can call the UnAdvice method of DccManSink to deregister DccManSink.

'To unregister the IDccManSink
objIDccMan.Unadvise(intAdvaiceReturn)

This example was intended to provide an example with the help of which we can get the notification on Connection and Disconnection, when any desktop machine is connected with Windows CE- based devices. I used it in my application for displaying the connection status between the desktop machine and the device.

GetNotificationOnConnect_src.zip