如何在WPF中使用MSMAPI32.ocx发送​​邮件?

时间:2013-11-29 12:30:27

标签: c# wpf activex

我们正在开发基于WPF的桌面应用程序,该应用程序具有用户可以向我们发送反馈的功能。我们可以收到姓名,电子邮件,正文等。

对于一些历史问题,我们使用 MSMAPI 来帮助我们发送邮件,随着时间的推移,我们发现它的所有功能都非常好直到我们在干净机器上进行测试

ActiveX控件说,请给我许可,这样我就可以继续了,这让我们很困惑,因为那个控件根本没有许可证。

好的,我现在就谈谈细节。

在文件夹C:\Windows\SysWOW64(在Win7 x64上),我们有msmapi32.ocx。从MSDN,我们必须包装它,因此可以在Windows窗体上托管。我们做了它,得到了两个程序集:MSMAPI.dllAxMSMAPI.dll,所以我们让我们的应用程序引用这两个DLL。

这是我们的代码(XAML):

<Window x:Class="WpfApplication14.MainWindow"
        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
        xmlns:ax="clr-namespace:AxMSMAPI;assembly=AxMSMAPI"
        Title="MainWindow"
        Width="525"
        Height="350">
    <StackPanel>
        <WindowsFormsHost>
            <ax:AxMAPIMessages Name="axMAPIMessage" />
        </WindowsFormsHost>

        <WindowsFormsHost>
            <ax:AxMAPISession Name="axMAPISession" />
        </WindowsFormsHost>
    </StackPanel>
</Window>

当然,我们必须将我们的项目构建目标更改为X86 ,否则会抛出ClassNotDefined异常。很好,按F5,主窗口显示成功。

然后我们复制我们的演示应用程序的Debug文件夹,双击,Oops ......它说, WpfAPplication14已停止工作。我们捕获了exption,这是堆栈:

System.Windows.Markup.XamlParseException occurred
  _HResult=-2146233087
  _message='Initialization of 'AxMSMAPI.AxMAPIMessages' threw an exception.' Line number '-' and line position '-'.
  HResult=-2146233087
  IsTransient=false
  Message='Initialization of 'AxMSMAPI.AxMAPIMessages' threw an exception.' Line number '-' and line position '-'.
  Source=PresentationFramework
  LineNumber=-
  LinePosition=-
  StackTrace:
       at System.Windows.Markup.WpfXamlLoader.Load(XamlReader xamlReader, IXamlObjectWriterFactory writerFactory, Boolean skipJournaledProperties, Object rootObject, XamlObjectWriterSettings settings, Uri baseUri)
  InnerException: System.ComponentModel.LicenseException
       _HResult=-2146232063
       _message=You must have a license to use this ActiveX control.
       HResult=-2146232063
       IsTransient=false
       Message=You must have a license to use this ActiveX control.
       Source=System.Windows.Forms
       StackTrace:
            at System.Windows.Forms.AxHost.CreateInstance()
            at System.Windows.Forms.AxHost.GetOcxCreate()
            at System.Windows.Forms.AxHost.TransitionUpTo(Int32 state)
            at System.Windows.Forms.AxHost.CreateHandle()
            at System.Windows.Forms.Control.CreateControl(Boolean fIgnoreVisible)
            at System.Windows.Forms.Control.CreateControl(Boolean fIgnoreVisible)
            at System.Windows.Forms.AxHost.EndInit()
            at MS.Internal.Xaml.Runtime.ClrObjectRuntime.InitializationGuard(XamlType xamlType, Object obj, Boolean begin)
       InnerException:
然后我们编写了一个Windows Forms应用程序,在开始的时候我们用WPF演示做了同样的事情,将两个DLL引用到项目中,甚至结果是一样的。它只能在我们的开发机器上显示窗口,不能在干净的测试机器上运行。

因此,我们在MSDN上执行了一些步骤,将ActiveX控件(C:\Windows\SysWOW64\msmapi32.ocx)添加到Visual Studio Toolbox,并将它们拖到曲面上,并且它在Test Machine上运行良好。

我们最后一次尝试是,按照Windows Forms演示,我们打算将ocx添加到工具箱,但是Visual Studio说它已成功添加到工具箱中,但它未在活动设计器中启用由于与当前设计器和.NET框架版本(VS2012 / .NET 4.0 / WPF)不兼容。

我们不知道在测试机器中解析XAML时,演示窗口抛出异常的原因是什么,似乎我们需要许可证,但它是否需要许可证?

我们尝试按照Windows Forms演示实现它,但我们甚至无法将ocx添加到工具箱中。

因此,如果您对以下问题或其中任何问题有任何建议,请随时告诉我们:

  • msmapi32.ocx来自哪里?有没有Windows机器有它或只有安装后的东西。 顺便说一句,我们还试图在我们的测试机上安装Office 2013,它会引发同样的异常。
  • 我们知道我们的ocx版本是6.0,它是在2000年发布的。所以如果我们想在我们的WPF应用程序中使用它,有什么建议吗?
  • 哪些因素会影响这个? 我们搜索了Dev和Test机器,两者都在文件夹中有ocx,并且两个注册表都有MSAPI相关项(并且Windows窗体非常好)。
  • 因此,如果可以回答上述问题,它可以帮助我们很多。根据您的经验,如何使用WPF,使用.NET提供的本机API或其他第三方控件/插件来实现此功能?实际上,我们的要求非常严格,以至于用户将反馈发送到某个固定地址。这就是我们所需要做的一切。

非常感谢您对我们的问题有所了解,并随时向我们提出令您困惑的问题。

感谢。

2 个答案:

答案 0 :(得分:0)

我的帖子不是您问题的答案,但提供了解决方案(如果您喜欢的话) 在过去,我使用过这个类(mapi) 此类不使用本机SmtpClient类(发送电子邮件但不与您的默认邮件应用程序交互),但能够调用您的电子邮件应用程序和弹出电子邮件窗口(填充您需要的每个详细信息),以便您的客户可以根据需要进行修改 更多,发送的电子邮件仍为“已发送电子邮件”文件夹...

enum HowTo { MAPI_ORIG = 0, MAPI_TO, MAPI_CC, MAPI_BCC };

public class MAPI
{
    [DllImport("MAPI32.DLL")]
    static extern int MAPISendMail(IntPtr sess, IntPtr hwnd, MapiMessage message, int flg, int rsv);

    [StructLayout(LayoutKind.Sequential, CharSet = CharSet.Ansi)]
    public class MapiMessage
    {
        public int reserved;
        public string subject;
        public string noteText;
        public string messageType;
        public string dateReceived;
        public string conversationID;
        public int flags;
        public IntPtr originator;
        public int recipCount;
        public IntPtr recips;
        public int fileCount;
        public IntPtr files;
    }

    [StructLayout(LayoutKind.Sequential, CharSet = CharSet.Ansi)]
    public class MapiFileDesc
    {
        public int reserved;
        public int flags;
        public int position;
        public string path;
        public string name;
        public IntPtr type;
    }

    [StructLayout(LayoutKind.Sequential, CharSet = CharSet.Ansi)]
    public class MapiRecipDesc
    {
        public int reserved;
        public int recipClass;
        public string name;
        public string address;
        public int eIDSize;
        public IntPtr entryID;
    }

    List<MapiRecipDesc> m_recipients = new List<MapiRecipDesc>();
    List<string> m_attachments = new List<string>();
    private int m_lastError = 0;
    private const int MAPI_LOGON_UI = 0x00000001;
    private const int MAPI_DIALOG = 0x00000008;
    private const int maxAttachments = 20;

    #region Private methods
    private bool AddRecipients(HowTo howTo, params string[] emails)
    {
        bool ret = true;
        foreach (string email in emails)
        {
            try
            {
                MapiRecipDesc recipient = new MapiRecipDesc();

                recipient.recipClass = (int)howTo;
                recipient.name = email;
                m_recipients.Add(recipient);
            }
            catch { ret = false; }
        }
        return ret;
    }
    private int SendMail(string strSubject, string strBody, int how)
    {
        MapiMessage msg = new MapiMessage();
        msg.subject = strSubject;
        msg.noteText = strBody;

        msg.recips = GetRecipients(out msg.recipCount);
        msg.files = GetAttachments(out msg.fileCount);

        m_lastError = MAPISendMail(new IntPtr(0), new IntPtr(0), msg, how, 0);
        if (m_lastError > 1)
            MessageBox.Show("MAPISendMail failed! " + LastError, "MAPISendMail");

        Cleanup(ref msg);
        return m_lastError;
    }
    private IntPtr GetRecipients(out int recipCount)
    {
        recipCount = 0;
        if (m_recipients.Count == 0)
            return IntPtr.Zero;

        int size = Marshal.SizeOf(typeof(MapiRecipDesc));
        IntPtr intPtr = Marshal.AllocHGlobal(m_recipients.Count * size);

        int ptr = (int)intPtr;
        foreach (MapiRecipDesc mapiDesc in m_recipients)
        {
            Marshal.StructureToPtr(mapiDesc, (IntPtr)ptr, false);
            ptr += size;
        }

        recipCount = m_recipients.Count;
        return intPtr;
    }
    private IntPtr GetAttachments(out int fileCount)
    {
        fileCount = 0;
        if (m_attachments == null)
            return IntPtr.Zero;

        if ((m_attachments.Count <= 0) || (m_attachments.Count > maxAttachments))
            return IntPtr.Zero;

        int size = Marshal.SizeOf(typeof(MapiFileDesc));
        IntPtr intPtr = Marshal.AllocHGlobal(m_attachments.Count * size);

        MapiFileDesc mapiFileDesc = new MapiFileDesc();
        mapiFileDesc.position = -1;
        int ptr = (int)intPtr;

        foreach (string strAttachment in m_attachments)
        {
            mapiFileDesc.name = Path.GetFileName(strAttachment);
            mapiFileDesc.path = strAttachment;
            Marshal.StructureToPtr(mapiFileDesc, (IntPtr)ptr, false);
            ptr += size;
        }

        fileCount = m_attachments.Count;
        return intPtr;
    }
    private void Cleanup(ref MapiMessage msg)
    {
        int size = Marshal.SizeOf(typeof(MapiRecipDesc));
        int ptr = 0;

        if (msg.recips != IntPtr.Zero)
        {
            ptr = (int)msg.recips;
            for (int i = 0; i < msg.recipCount; i++)
            {
                Marshal.DestroyStructure((IntPtr)ptr, typeof(MapiRecipDesc));
                ptr += size;
            }
            Marshal.FreeHGlobal(msg.recips);
        }

        if (msg.files != IntPtr.Zero)
        {
            size = Marshal.SizeOf(typeof(MapiFileDesc));

            ptr = (int)msg.files;
            for (int i = 0; i < msg.fileCount; i++)
            {
                Marshal.DestroyStructure((IntPtr)ptr, typeof(MapiFileDesc));
                ptr += size;
            }
            Marshal.FreeHGlobal(msg.files);
        }

        m_recipients.Clear();
        m_attachments.Clear();
        m_lastError = 0;
    }
    #endregion

    #region Public methods
    public bool AddTo(params string[] emails)
    {
        return AddRecipients(HowTo.MAPI_TO, emails);
    }
    public bool AddCC(params string[] emails)
    {
        return AddRecipients(HowTo.MAPI_CC, emails);
    }
    public bool AddBCC(params string[] emails)
    {
        return AddRecipients(HowTo.MAPI_BCC, emails);
    }
    public void AddAttachment(string strAttachmentFileName)
    {
        m_attachments.Add(strAttachmentFileName);
    }

    public int SendMailPopup(string strSubject, string strBody)
    {
        return SendMail(strSubject, strBody, MAPI_LOGON_UI | MAPI_DIALOG);
    }
    public int SendMailDirect(string strSubject, string strBody)
    {
        return SendMail(strSubject, strBody, MAPI_LOGON_UI);
    }

    public string LastError
    {
        get
        {
            switch (m_lastError)
            {
                case 0: return "OK";
                case 1: return "User abort [1]";
                case 2: return "General MAPI failure [2]";
                case 3: return "MAPI login failure [3]";
                case 4: return "Disk full [4]";
                case 5: return "Insufficient memory [5]";
                case 6: return "Access denied [6]";
                case 7: return "-unknown- [7]";
                case 8: return "Too many sessions [8]";
                case 9: return "Too many files were specified [9]";
                case 10: return "Too many recipients were specified [10]";
                case 11: return "A specified attachment was not found [11]";
                case 12: return "Attachment open failure [12]";
                case 13: return "Attachment write failure [13]";
                case 14: return "Unknown recipient [14]";
                case 15: return "Bad recipient type [15]";
                case 16: return "No messages [16]";
                case 17: return "Invalid message [17]";
                case 18: return "Text too large [18]";
                case 19: return "Invalid session [19]";
                case 20: return "Type not supported [20]";
                case 21: return "A recipient was specified ambiguously [21]";
                case 22: return "Message in use [22]";
                case 23: return "Network failure [23]";
                case 24: return "Invalid edit fields [24]";
                case 25: return "Invalid recipients [25]";
                case 26: return "Not supported [26]";
                default: return String.Format("MAPI error [{0}]", m_lastError);
            }
        }
    }
    #endregion
}

答案 1 :(得分:0)

您是否尝试过注册ocx? (确保尚未注册较新的ocx)

我过去曾使用本机.NET API发送邮件。这是一段代码:

/// <summary>
      ///Method to Send an Email informing interested parties about the status of data extraction. 
      /// INPUTS : int iProcessIsSuccess : int informing about the success of the process. -1 means failure, 0 means partial success, 1 means success. 
      ///          string szLogDataToBeSent :  Log data to be sent incase process not successful.
      /// OUTPUTS : bool. True if success, else false.
      /// </summary>
      public bool SendEmailNotification(string szEmailAddressFileName, int iProcessIsSuccess, string szLogDataToBeSent)
      {
         bool bSuccess = false;

         //the the SMTP host.
         SmtpClient client = new SmtpClient();

         //SMTP Server
         client.Host = CommonVariables.EMAIL_SMTP_SERVER;

         //SMTP Credentials
         client.Credentials = new NetworkCredential(CommonVariables.EMAIL_USERNAME, CommonVariables.EMAIL_PASSWORD);

         //Creating a new mail.
         MailMessage mail = new MailMessage();

         //Filling 'From' Tab.
         mail.From = new MailAddress(CommonVariables.EMAIL_SENDERS_ADDRESS, CommonVariables.EMAIL_SENDERS_NAME);

         //Filling 'To' tab.
         List<EmailAddress> EmailAddressList = new List<EmailAddress>();
         try
         {
            using (System.IO.FileStream fs = new FileStream(szEmailAddressFileName, FileMode.Open))
            {
               XmlSerializer xs = new XmlSerializer(typeof(List<EmailAddress>));
                EmailAddressList = xs.Deserialize(fs) as List<EmailAddress>;
            }

            foreach (EmailAddress addr in EmailAddressList)
            {
               mail.To.Add(addr.RecepientEmailAddress);
            }
         }
         catch(Exception Ex)
         {
            mail.To.Add("somedefaultemail@companyname.com");
         }

         //Filling mail body.
         string szMailBody = "";
         string szMailSubject = "";

         if (1 == iProcessIsSuccess) //Success
         {
            szMailSubject = String.Format(CommonVariables.EMAIL_SUBJECT_BOILER_PLATE, "a SUCCESS");
            szMailBody = String.Format(CommonVariables.EMAIL_BODY_BOILER_PLATE, DateTime.UtcNow.ToString(), Environment.MachineName);
            szMailBody += "\r\n" + szMailSubject + "\r\n";

         }
         else if (0 == iProcessIsSuccess) //Partially Success
         {
            szMailSubject = String.Format(CommonVariables.EMAIL_SUBJECT_BOILER_PLATE, "a PARTIAL SUCCESS"); ;
            szMailBody = String.Format(CommonVariables.EMAIL_BODY_BOILER_PLATE, DateTime.UtcNow.ToString(), Environment.MachineName);
            szMailBody += "\r\n"+ szMailSubject + "\r\n";
            szMailBody += "\r\n" + "The Log data is as follows:\r\n";
            szMailBody += szLogDataToBeSent;
            mail.Priority = MailPriority.High;
         }
         else //Failed
         {
            szMailSubject = String.Format(CommonVariables.EMAIL_SUBJECT_BOILER_PLATE, "a FAILURE"); ;
            szMailBody = String.Format(CommonVariables.EMAIL_BODY_BOILER_PLATE, DateTime.UtcNow.ToString(), Environment.MachineName);
            szMailBody += "\r\n" + szMailSubject + "\r\n";
            szMailBody += "\r\n" + "The Log data is as follows:\r\n";
            szMailBody += szLogDataToBeSent;
            mail.Priority = MailPriority.High;
         }

         mail.Body = szMailBody;

         mail.Subject = szMailSubject;

         //Send Email.
         try
         {
            client.Send(mail);
            bSuccess = true;
         }
         catch (Exception Ex)
         {
            bSuccess = false;
         }

         // Clean up.
         mail.Dispose();


         return bSuccess;

      }