Click here to Skip to main content
Click here to Skip to main content
Go to top

Developing Managed Event Sinks for Exchange Server Using Visual Basic.Net

, 2 Feb 2007
Rate this:
Please Sign up or sign in to vote.
Developing Managed Event Sinks for Exchange Server using VB.Net

Introduction

I use Event Sinks with Exchange Server 2003 frequently. Most of these were written in VB6 and I wanted to begin migrating them over to .Net and use Visual Studio 2005 as the development tool. In searching for coding help I encountered the article Developing Managed Event Sinks/Hooks for Exchange Server Store using C# by Logu Krishnan here at The Code Project. Although written in C# it was very illuminating as to the process required. The steps to do this project in VB.Net are not drastically different but they do require some differences. When I searched other areas for code samples, I never found any that did as good a job as Logu Krishnan had done with his article.

Exchange Store Events

This article focuses on Asynchronous Events. Specifically the events are OnSyncSave and OnSyncDelete. The article by Logu Krishnan previously referenced has an excellent description of Exchange Store Events.

The Purpose of the Sink

This sink is designed to be implemented against a mail enabled public folder. It fires each time a message is saved or deleted in the folder. The code extracts any attachments from the message, saves them to a target network location, copies the message to a sub folder named "Processed" and then deletes it from the original folder. I have not included the code for actually processing the attachment but it is fairly straightforward and I do a variety of tasks with the attachments based on the purpose of the folder. I have included detailed steps to create and implement the sink.

Create the Project

Create your project using the Windows Class Library template. I have named this project EventSinkNet.

Mark for COM Interop

Be sure to mark the project to Register for Comp Interop by clicking on Project from the menu, choosing EventSinkNet Properties, selecting the Compile tab on the left and clicking on Register for COM Interop at the bottom.

Copy Required Files to Project

  • Copy adodb.dll (file version 7.10.3077.0) from \Program Files\Microsoft.NET\Primary Interop.Assemblies to project directory.
  • Copy codex.dll (Microsoft CDO for Microsoft Exchange Library - file version 6.5.7650.29) from \Program Files\Common Files\Microsoft Shared\CDO\cdoex.dll. This was on my Exchange Server.
  • Copy exoledb.dll (Microsoft Exchange OLEDB Server - file version 6.5.7651.60) from \exchsrvr\bin\exoledb.dll). This was on my Exchange Server.
  • Copy exevtsnk.tlb (Type Library - Size 11,976 bytes) from \Program Files\Exchange SDK\SDK\Support\OLEDB\exevtsnk.tlb

Create Strong Name Keys

Use the Visual Studio Command Prompt and navigate to the project folder. Create the strong name keys with the following commands.

  1. sn.exe -k adodb.key
  2. sn.exe -k cdoex.key
  3. sn.exe -k exoledb.key
  4. sn.exe -k exevtsnk.key

Create Interop Assemblies

  • Open the Visual Studio 2005 Command Prompt and navigate to the project folder.
  • Key in the following command to create the exoledb assembly
    tlbimp exoledb.dll /keyfile:exoledb.key /out:interop.exoledb.dll

    The output from the command may be reflect the following error but can be ignored

  • Key in the following command to create the cdoex assembly

    tlbimp cdoex.dll /keyfile:cdoex.key /out:interop.cdoex.dll

    The output from the command should reflect the following

  • Key in the following command to create the exevtsnk assembly

    tlbimp exevtsnk.dll /keyfile:exevtsnk.key /out:interop.exevtsnk.dll

    The output from the command may be reflect the following error but can be ignored

Add References to Your Project

Add references to the four dll's that are in your project directory.

Add a reference to System.EnterpriseServices

Your reference section in you Solution Explorer should appear as follows

Modify the AssemblyInfo.vb File

Add the following to the top of the file

Imports System.EnterpriseServices

Insert the following lines

[Assembly: AssemblyKeyFile(
    "EventSinkNet.snk")]
[Assembly: AssemblyKeyName(
    "EventSinkNet")]
[Assembly: ApplicationActivation(ActivationOption.Server)>
[Assembly: ApplicationName(
    "EventSinkDLL")>

The Code

The sink acts on each message after it is saved to the store. It opens each message and extracts each attachment to a file on a network share. It then copies the message to a subfolder named "Processed" and deletes the original message.

Option Explicit On
Option Strict On

'Add project references to the System.EnterpriseServices, 
'ADODB, Interop.Exoledb, and SignedExevtsnk .NET components.
Imports System.IO
Imports System.EnterpriseServices
Imports Exoledb = Interop.Exoledb
Imports ExevtsnkLib = Interop.Exevtsnk
Imports CDO = Interop.cdoex
Imports ADODB

Namespace EvSink
    Public Class ASyncEvents
        Inherits ServicedComponent
        Implements Exoledb.IExStoreAsyncEvents

        ' Logfile path.
        Private Const LOGFILE As String = "C:\\evtlog.txt"
        Private Const WORKPATH As String = "\\apps00\
            shared$\SSWork\"

        Public Sub OnDelete(ByVal pEventInfo As interop
            .exoledb.IExStoreEventInfo, _
            ByVal bstrURLItem As String, ByVal lFlags 
            As Integer) _
            Implements interop.exoledb.IExStoreAsyncEvents
            .OnDelete
            ' do something here 
        End Sub

        Public Sub OnSave(ByVal pEventInfo As interop
            .exoledb.IExStoreEventInfo, _
            ByVal bstrURLItem As String, ByVal lFlags 
            As Integer) _
            Implements interop.exoledb.IExStoreAsyncEvents
            .OnSave
            Dim sr As StreamWriter
            Dim msg As CDO.IMessage = New CDO.Message
            Dim atch As CDO.IBodyPart

            Dim rec As ADODB.Record
            Dim i As Integer
            Dim sURLSuffix As String
            Dim sURLPrefix As String
            Dim sURLItemTo As String
            Dim sAtch As String

            ' Open the log file, append text to file.
            sr = File.AppendText(LOGFILE)
            sr.WriteLine("In onsave")
            
            ' Parse out the components of the URL
            i = InStrRev(bstrURLItem, "/", -1, 
                CompareMethod.Text)
            sURLSuffix = Right(bstrURLItem, Len(
                bstrURLItem) - i)
            sURLPrefix = Left(bstrURLItem, i)
            sURLItemTo = sURLPrefix & "processed/" & 
                         sURLSuffix

            ' Get the message
            Try
                msg.DataSource.Open(bstrURLItem, _
                             Nothing, _
                             ConnectModeEnum.adModeRead, _
                             RecordCreateOptionsEnum
                                .adFailIfNotExists, _
                             RecordOpenOptionsEnum
                                .adOpenSource, _
                             Nothing, Nothing)
                sr.WriteLine("Opened message")
                ' process it
                If msg.Attachments.Count > 0 Then
                    For Each atch In msg.Attachments
                        sAtch = atch.FileName
                        atch.SaveToFile(WORKPATH & sAtch)
                        sr.WriteLine("Saved as: " & sAtch)
                    Next

                End If
                ' save it to processed folder
                msg.DataSource.SaveTo(sURLItemTo)
                sr.WriteLine("Saved to: " & sURLItemTo)
                atch = Nothing
                msg = Nothing

                ' delete it
                rec = New ADODB.Record
                rec.Open(sURLPrefix, , ConnectModeEnum
                    .adModeReadWrite)
                rec.DeleteRecord(sURLSuffix)
                sr.WriteLine("Deleted record")
                rec.Close()
            Catch ex As Exception
                sr.WriteLine("Record Delete Exception 
                    message: " & ex.Message)
            End Try
            
            sr.Close()
        End Sub
    End Class
End Namespace

Create a Key Pair for the DLL

sn -k EventSinkNet.snk

Compile and Copy

I had to manually copy the adodb.dll to my Debug folder. Now copy the files from your Debug or Release folder to a folder on the Exchange Server.

Register the Assembly

On the Exchange Server, open a command prompt in the folder containing the sink. Run the regasm.exe command as shown below. The command should indicate "Types registered successfully".

Regasm.exe EventSinkNet.dll /codebase 

Create the Component Service

Open the Administrative Tools/Component Services to install the dll. I create an empty application named "EventSinkNet" and clicked through the default options. I assigned a user to the Application Identity account to run the sink.

Install the Component

I then installed the component by select the Component Folder under the new component named "EventSinkNet" and choosing the "New" option under the properties. I selected "Import component(s) that are already registered" and located the component named EventSinkNet.EvSink.ASyncEvents.

Register the Sink

The sink can be registered to any Exchange folder. A script file like the one below can be used to register the sink or you can use Exchange Explorer with comes with the Exchange SDK.

License

This article has no explicit license attached to it but may contain usage terms in the article text or the download files themselves. If in doubt please contact the author via the discussion board below.

A list of licenses authors might use can be found here

Share

About the Author

Andy McNiece
Web Developer
United States United States
No Biography provided

Comments and Discussions

 
QuestionHow to get public folder path? Pinmemberbaburman18-May-10 9:07 
AnswerRe: How to get public folder path? PinmemberAndy McNiece18-May-10 14:26 
GeneralRe: How to get public folder path? Pinmemberbaburman18-May-10 22:31 
GeneralRe: How to get public folder path? PinmemberAndy McNiece19-May-10 3:55 
GeneralRe: How to get public folder path? Pinmemberbaburman19-May-10 21:18 
GeneralRe: How to get public folder path? Pinmemberbaburman28-May-10 1:47 
GeneralRe: How to get public folder path? PinmemberAndy McNiece28-May-10 4:06 
GeneralRe: How to get public folder path? Pinmemberbaburman28-May-10 7:04 
GeneralRe: How to get public folder path? Pinmemberbaburman29-May-10 20:12 
GeneralDetails of modified occurance of recurring meeting is not getting in EventSink [modified] Pinmemberranjitcherian29-Jun-09 3:17 
GeneralAttach events to any user mailbox Pinmembereyanson13-Oct-08 8:06 
GeneralRe: Attach events to any user mailbox Pinmembereyanson13-Oct-08 10:41 
QuestionPermission for access to message PinmemberMember 21013325-Jun-08 22:49 
AnswerRe: Permission for access to message PinmemberAndy McNiece2-Jul-08 5:31 
GeneralRe: Permission for access to message PinmemberMIRo2k2-Jul-08 5:59 
QuestionIAsyncNotify Interface - returning S_PENDING to process item on another thread PinmemberMember 291900916-Mar-08 23:42 
GeneralEventsink stops PinmemberDabu125-Jan-08 1:35 
GeneralRe: Eventsink stops PinmemberAndy McNiece27-Jan-08 6:49 
QuestionAccess denied, error open record Pinmemberjch000131-Oct-07 5:01 
Generalevents wont fire Pinmemberboaz.jan11-Aug-07 7:23 
GeneralRe: events wont fire PinmemberAndy McNiece13-Aug-07 6:31 
GeneralRe: events wont fire Pinmemberboaz.jan13-Aug-07 7:04 
GeneralRe: events wont fire PinmemberAndy McNiece13-Aug-07 7:18 
QuestionCannot register using cscript RegEvent.vbs PinmemberAximili31-Jul-07 17:01 
AnswerRe: Cannot register using cscript RegEvent.vbs PinmemberAndy McNiece1-Aug-07 4:13 

General General    News News    Suggestion Suggestion    Question Question    Bug Bug    Answer Answer    Joke Joke    Rant Rant    Admin Admin   

Use Ctrl+Left/Right to switch messages, Ctrl+Up/Down to switch threads, Ctrl+Shift+Left/Right to switch pages.

| Advertise | Privacy | Mobile
Web04 | 2.8.140921.1 | Last Updated 2 Feb 2007
Article Copyright 2007 by Andy McNiece
Everything else Copyright © CodeProject, 1999-2014
Terms of Service
Layout: fixed | fluid