我们正在开发基于WPF的桌面应用程序,该应用程序具有用户可以向我们发送反馈的功能。我们可以收到姓名,电子邮件,正文等。
对于一些历史问题,我们使用 MSMAPI 来帮助我们发送邮件,随着时间的推移,我们发现它的所有功能都非常好直到我们在干净机器上进行测试。
ActiveX控件说,请给我许可,这样我就可以继续了,这让我们很困惑,因为那个控件根本没有许可证。
好的,我现在就谈谈细节。
在文件夹C:\Windows\SysWOW64
(在Win7 x64上),我们有msmapi32.ocx
。从MSDN,我们必须包装它,因此可以在Windows窗体上托管。我们做了它,得到了两个程序集:MSMAPI.dll
和AxMSMAPI.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,它会引发同样的异常。 非常感谢您对我们的问题有所了解,并随时向我们提出令您困惑的问题。
感谢。
答案 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;
}