none
Transport agent problems with Exchange 2010 SP2 RRS feed

  • Question

  • Hi all,

    I am new with Exchange development.

    I try to install Exchange SDK Antivirus sample to Exchange 2010 SP2 on Windows Server 2008 R2 64 bit.

    I built the sample and deployed it to the Exchange using install script. "Get-TransportAgent" command of  Exchange Management shell shows that Antivirus agent enabled. But few seconds after installation I see that MSExchangeTransport service is down. I can restart it but it down one more time. I simplified the Antivirus agent - I don't call COM object in the handler methods, only call Debug.WriteLine but the behavior is the same. When I uninstalled Antivirus agent - MSExchangeTransport  works without problem.

    What is the problem?

    Thanks in advance, Vitaly

    Wednesday, April 18, 2012 3:06 PM

All replies

  • Hi,

    So you've simplified the agent down to "Hello World" and it still goes legs-up ?

    Can you share your code ?

    Regards,


    Scott Quinn | C# developer & messaging specialist (for hire). Contact me at http://au.linkedin.com/in/scottquinn

    Wednesday, April 18, 2012 4:30 PM
  • Hi,

    First of all I built it as is in the Microsoft example.

    But to simplify it i do the following:

    // ***************************************************************
    // <copyright file="GatewayAntivirusAgent.cs" company="Microsoft">
    //     Copyright (C) Microsoft Corporation.  All rights reserved.
    // </copyright>
    // <summary>
    // Sends incoming messages to an out-of-process COM server, which
    // asynchronously examines the message and returns a modified
    // version of the message.
    // </summary>
    // ***************************************************************

    namespace Microsoft.Exchange.Samples.Antivirus
    {
        using System;
        using System.IO;
        using System.Diagnostics;
        using System.Runtime.InteropServices;
        using Microsoft.Exchange.Data.Transport;
        using Microsoft.Exchange.Data.Transport.Smtp;
        using Microsoft.Exchange.Samples.Antivirus;

        /// <summary>
        /// Agent factory for the ComInterop sample
        /// </summary>
        public class GatewayAntivirusAgentFactory : SmtpReceiveAgentFactory
        {
            /// <summary>
            /// Create a new AntivirusAgent
            /// </summary>
            /// <param name="server">Exchange Gateway server</param>
            /// <returns>a new AntivirusAgent</returns>
            public override SmtpReceiveAgent CreateAgent(SmtpServer server)
            {
                return new GatewayAntivirusAgent();
            }
        }

        /// <summary>
        /// SmtpReceiveAgent for the ComInterop sample
        /// </summary>
        public class GatewayAntivirusAgent : SmtpReceiveAgent, IComCallback
        {
            /// <summary>
            /// Class ID for the unmanaged service
            /// </summary>
            private static Guid unmanagedClsid = new Guid("B71FEE9E-25EF-4e50-A1D2-545361C90E88");

            /// <summary>
            /// This context to allow Exchange to continue processing a message
            /// </summary>
            private AgentAsyncContext agentAsyncContext;

            /// <summary>
            /// The current MailItem
            /// </summary>
            private MailItem mailItem;

            /// <summary>
            /// Virus scanner
            /// </summary>
            IComInvoke virusScanner;

            /// <summary>
            /// The constructor registers an end of data event handler
            /// </summary>
            public GatewayAntivirusAgent()
            {
                Debug.WriteLine("[AntivirusAgent] agent constructor");
                //this.OnEndOfData += this.EndOfDataHandler;
            }

            /// <summary>
            /// Invoked by Exchange when a message has been submitted
            /// </summary>
            /// <param name="source">the source of this event</param>
            /// <param name="args">arguments for this event</param>
            void EndOfDataHandler(ReceiveMessageEventSource source, EndOfDataEventArgs args)
            {
                Debug.WriteLine("[AntivirusAgent] Invoking the COM service");            
    /*
                try
                {
                    // Create the virus scanner COM object
                    Guid classGuid = new Guid("B71FEE9E-25EF-4e50-A1D2-545361C90E88");
                    Guid interfaceGuid = new Guid("7578C871-D9B3-455a-8371-A82F7D864D0D");

                    object virusScannerObject = UnsafeNativeMethods.CoCreateInstance(
                        classGuid,
                        null,
                        4, // CLSCTX_LOCAL_SERVER,
                        interfaceGuid);

                    this.virusScanner = (IComInvoke)virusScannerObject;

                    // GetAgentAsyncContext causes Exchange to wait for this agent
                    // to invoke the returned callback before continuing to
                    // process the current message.
                    this.agentAsyncContext = this.GetAgentAsyncContext();

                    this.mailItem = args.MailItem;

                    // Invoke the virus scanner
                    this.virusScanner.BeginVirusScan((IComCallback)this);
                }
                catch (System.Runtime.InteropServices.COMException ex)
                {
                    Debug.WriteLine("[AntivirusAgent] " + ex.ToString());
                    this.agentAsyncContext.Complete();
                }

     */
                return;
            }

            #region IComCallback Members

            /// <summary>
            /// This will be invoked by the COM server when it has finished
            /// processing the message.
            /// </summary>
            public void VirusScanCompleted()
            {
                Debug.WriteLine("[AntivirusAgent] Callback from the COM service");

                // This allows Exchange to continue processing the message
                this.agentAsyncContext.Complete();

                // Release the agent manager resources
                this.agentAsyncContext = null;

                // Release the COM server resources
                this.virusScanner = null;
            }

            /// <summary>
            /// Replace the MailItem's MimeStream with the given stream
            /// </summary>
            /// <param name="stream">a stream containing new content for the message</param>
            public void SetContentStream(object stream)
            {
                using (Stream newContent = new DotNetStream((ComInterop.IStream)stream))
                {
                    using (Stream writeStream = this.mailItem.GetMimeWriteStream())
                    {
                        int bytesRead = 0;
                        byte[] buffer = new byte[4000];
                        while ((bytesRead = newContent.Read(buffer, 0, buffer.Length)) > 0)
                        {
                            writeStream.Write(buffer, 0, bytesRead);
                        }
                        writeStream.Flush();
                    }
                }
            }

            /// <summary>
            /// Return the MailItem's MimeStream
            /// </summary>
            /// <param name="stream">a stream containing message's current content</param>
            public void GetContentStream(out ComInterop.IStream stream)
            {
                stream = new ComStream(this.mailItem.GetMimeReadStream());
            }

            #endregion
        }
    }

    // ***************************************************************
    // <copyright file="BridgeheadAntivirusAgent.cs" company="Microsoft">
    //     Copyright (C) Microsoft Corporation.  All rights reserved.
    // </copyright>
    // <summary>
    // Sends incoming messages to an out-of-process COM server, which
    // asynchronously examines the message and returns a modified
    // version of the message.
    // </summary>
    // ***************************************************************

    namespace Microsoft.Exchange.Samples.Antivirus
    {
        using System;
        using System.IO;
        using System.Diagnostics;
        using System.Runtime.InteropServices;
        using Microsoft.Exchange.Data.Transport;
        using Microsoft.Exchange.Data.Transport.Routing;
        using Microsoft.Exchange.Samples.Antivirus;

        /// <summary>
        /// Agent factory for the ComInterop sample
        /// </summary>
        public class AntivirusAgentFactory : RoutingAgentFactory
        {
            /// <summary>
            /// Create a new AntivirusAgent
            /// </summary>
            /// <param name="server">Exchange Gateway server</param>
            /// <returns>a new AntivirusAgent</returns>
            public override RoutingAgent CreateAgent(SmtpServer server)
            {
                return new AntivirusAgent();
            }
        }

        /// <summary>
        /// SmtpReceiveAgent for the ComInterop sample
        /// </summary>
        public class AntivirusAgent : RoutingAgent, IComCallback
        {
            /// <summary>
            /// Class ID for the unmanaged service
            /// </summary>
            private static Guid unmanagedClsid = new Guid("B71FEE9E-25EF-4e50-A1D2-545361C90E88");

            /// <summary>
            /// This context to allow Exchange to continue processing a message
            /// </summary>
            private AgentAsyncContext agentAsyncContext;

            /// <summary>
            /// The current MailItem
            /// </summary>
            private MailItem mailItem;

            /// <summary>
            /// Virus scanner
            /// </summary>
            IComInvoke virusScanner;

            /// <summary>
            /// The constructor registers an end of data event handler
            /// </summary>
            public AntivirusAgent()
            {
                Debug.WriteLine("[AntivirusAgent] agent constructor");
                //this.OnSubmittedMessage += new SubmittedMessageEventHandler(this.SubmittedMessageHandler);
            }

            /// <summary>
            /// Invoked by Exchange when a message has been submitted
            /// </summary>
            /// <param name="source">the source of this event</param>
            /// <param name="args">arguments for this event</param>
            void SubmittedMessageHandler(SubmittedMessageEventSource source, QueuedMessageEventArgs args)
            {
                Debug.WriteLine("[AntivirusAgent] Invoking the COM service");            

                /*
                try
                {
                    // Create the virus scanner COM object
                    Guid classGuid = new Guid("B71FEE9E-25EF-4e50-A1D2-545361C90E88");
                    Guid interfaceGuid = new Guid("7578C871-D9B3-455a-8371-A82F7D864D0D");

                    object virusScannerObject = UnsafeNativeMethods.CoCreateInstance(
                        classGuid,
                        null,
                        4, // CLSCTX_LOCAL_SERVER,
                        interfaceGuid);

                    this.virusScanner = (IComInvoke)virusScannerObject;

                    // GetAgentAsyncContext causes Exchange to wait for this agent
                    // to invoke the returned callback before continuing to
                    // process the current message.
                    this.agentAsyncContext = this.GetAgentAsyncContext();

                    this.mailItem = args.MailItem;

                    // Invoke the virus scanner
                    this.virusScanner.BeginVirusScan((IComCallback)this);
                }
                catch (System.Runtime.InteropServices.COMException ex)
                {
                    Debug.WriteLine("[AntivirusAgent] " + ex.ToString());
                    if (this.agentAsyncContext != null)
                    {
                        this.agentAsyncContext.Complete();
                    }
                }
                */
                return;
            }

            #region IComCallback Members

            /// <summary>
            /// This will be invoked by the COM server when it has finished
            /// processing the message.
            /// </summary>
            public void VirusScanCompleted()
            {
                Debug.WriteLine("[AntivirusAgent] Callback from the COM service");

                // This allows Exchange to continue processing the message
                this.agentAsyncContext.Complete();

                // Release the agent manager resources
                this.agentAsyncContext = null;

                // Release the COM server resources
                this.virusScanner = null;
            }

            /// <summary>
            /// Replace the MailItem's MimeStream with the given stream
            /// </summary>
            /// <param name="stream">a stream containing new content for the message</param>
            public void SetContentStream(object stream)
            {
                using (Stream newContent = new DotNetStream((ComInterop.IStream)stream))
                {
                    using (Stream writeStream = this.mailItem.GetMimeWriteStream())
                    {
                        int bytesRead = 0;
                        byte[] buffer = new byte[4000];
                        while ((bytesRead = newContent.Read(buffer, 0, buffer.Length)) > 0)
                        {
                            writeStream.Write(buffer, 0, bytesRead);
                        }
                        writeStream.Flush();
                    }
                }
            }

            /// <summary>
            /// Return the MailItem's MimeStream
            /// </summary>
            /// <param name="stream">a stream containing message's current content</param>
            public void GetContentStream(out ComInterop.IStream stream)
            {
                stream = new ComStream(this.mailItem.GetMimeReadStream());
            }

            #endregion
        }

        /// <summary>
        /// P/Invoke support
        /// </summary>
        internal sealed class UnsafeNativeMethods
        {
            /// <summary>
            /// P/Invoke to ole32!CoCreateInstance, in order to create instance using CLSCTX
            /// </summary>
            [DllImport("ole32.dll", PreserveSig = false)]
            [return: MarshalAs(UnmanagedType.IUnknown)]
            internal static extern object CoCreateInstance(
                [MarshalAs(UnmanagedType.LPStruct)] Guid rclsid,
                [MarshalAs(UnmanagedType.IUnknown)] object pUnkOuter,
                uint dwClsContext,
                [MarshalAs(UnmanagedType.LPStruct)] Guid riid);
        }
    }

    May be the problem NET framework version installed on the machine?

    Thursday, April 19, 2012 8:08 AM
  • Hi,

    I debug it with WinDBG and it's seems that some assembly can't be loaded by MSExchangeTransport.exe.

    I get following stack trace:

    00000000`1d81e1c8 00000000`7724418b ntdll!NtTerminateProcess+0xa
    00000000`1d81e1d0 000007fe`f9d083d7 ntdll!RtlExitUserProcess+0x9b
    00000000`1d81e200 000007fe`fa10ff98 mscorwks!StrongNameErrorInfo+0xd39f
    00000000`1d81e480 000007fe`fa1af1b8 mscorwks!PreBindAssembly+0x1f208
    00000000`1d81e4b0 000007fe`f94a6878 mscorwks!ReOpenMetaDataWithMemory+0xf9d8
    00000000`1d81e660 000007fe`f21fb42a mscorlib_ni+0x8b6878
    00000000`1d81e6a0 000007fe`f21fd710 Microsoft_Exchange_Net_ni+0x50b42a
    00000000`1d81ea20 000007fe`f21fd67d Microsoft_Exchange_Net_ni+0x50d710
    00000000`1d81ea60 000007fe`f8783964 Microsoft_Exchange_Net_ni+0x50d67d
    00000000`1d81ea90 000007fe`f8783c54 System_ni+0x753964
    00000000`1d81eae0 000007fe`f95882a5 System_ni+0x753c54
    00000000`1d81eb30 000007fe`f8ee2bbb mscorlib_ni+0x9982a5
    00000000`1d81eb60 000007fe`f95881c1 mscorlib_ni+0x2f2bbb
    00000000`1d81ebb0 000007fe`f9d90542 mscorlib_ni+0x9981c1
    00000000`1d81ec00 000007fe`f9c74143 mscorwks!IEE+0xd9c2
    00000000`1d81ec50 000007fe`f9c73ff6 mscorwks!CreateAssemblyNameObject+0x60cb
    00000000`1d81ecf0 000007fe`f9bc95bf mscorwks!CreateAssemblyNameObject+0x5f7e
    00000000`1d81ed50 000007fe`fa117ae7 mscorwks!InitializeFusion+0xb543
    00000000`1d81edd0 000007fe`f9bbdae0 mscorwks!PreBindAssembly+0x26d57
    00000000`1d81ee70 000007fe`f9ca4025 mscorwks!GetMetaDataInternalInterfaceFromPublic+0xbdc8

    May be it somehow relates to 64 bit OS?

    Thursday, April 19, 2012 11:19 AM
  • Hi,

    Ummmm... just looking the code it 'looks' ok. However, before getting into it, while the AV sample is excellent (esp with the asynchronous completion and the COM) it's also the most complex of the SDK examples - esp if you don't need to do a COM interface.

    Have you tried one of simpler ones first to make sure it builds and runs on your test Exchange server ? I'd recommend the edge logging sample (or the hub logging sample if you're developing a routing agent). Just to check a fairly vanilla example works first would be good w/o the added complexity of COM interoperability...

    Regards,


    Scott Quinn | C# developer & messaging specialist (for hire). Contact me at http://au.linkedin.com/in/scottquinn

    Thursday, April 19, 2012 12:08 PM