如何在 Silverlight 4 应用程序中获取 Outlook 2003 数据
-
29-09-2019 - |
题
是否可以将 Outlook 2003 自动化与 Silverlight 4 结合使用?或者也许有一些不同的方法可以在 Silverlight 应用程序中使用 Outlook 2003 MAPI?
我正在使用 Silverlight 4,并尝试通过以下方式与 Outlook 交互:
dynamic outlook = AutomationFactory.GetObject("Outlook.Application");
对于 Outlook 2007/2010 一切正常。
但是,当我尝试使用 Outlook 2003 中的动态实例的任何字段(例如 Outlook.Session)时,我得到了 NotSupportedException。这只是 Outlook 2003 的问题。
我找到文章了 http://msdn.microsoft.com/en-us/library/aa159619%28office.11%29.aspx 但对于Silverlight应用程序来说它是没有用的(无法直接引用office程序集或COM)。
Type.GetTypeFromProgID
也没用,Silverlight不支持。
解决方案
我终于找到了答案。大多数操作都可以使用标准 Outlook 2003 对象模型来执行。所有这些操作都在 这篇微软文章. 。文章中的示例与 Silverlight 代码之间的主要区别 - 我们无法引用 Interop Outlook 程序集,因此我们需要使用动态。因此,从联系人列表或所有收件箱电子邮件中获取所有联系人非常容易(请参阅文章)。最困难的部分是获取已创建用户帐户的列表。Outlook 2003 对象模型提供了仅获取一个(默认)帐户的可能性:
dynamic outlook = AutomationFactory.CreateObject("Outlook.Application");
var ns = outlook.GetNamespace("MAPI");
var defaultAccount = ns.CurrentUser;
但它仍然不适合我。非常遗憾的是,Outlook 2003 对象模型中没有 Session.Accounts 属性。所以我发现只有一种棘手的方法来获取帐户列表。
public class Ol11ImportStrategy
{
const string registryPath = @"HKEY_CURRENT_USER\Software\Microsoft\Windows NT\CurrentVersion\Windows Messaging Subsystem\Profiles\Outlook\9375CFF0413111d3B88A00104B2A6676\{0}\{1}";
const string constAccountName = "Account Name";
const string constEmail = "Email";
const string constSMTPServer = "SMTP Server";
const string constName = "Display Name";
const string constIMAPServer = "IMAP Server";
const string constPOP3Server = "POP3 Server";
const string constValueClsid = "clsid";
const string constContentsAccountClsid_POP3 = "{ED475411-B0D6-11D2-8C3B-00104B2A6676}";
const string constContentsAccountClsid_IMAP = "{ED475412-B0D6-11D2-8C3B-00104B2A6676}";
public IEnumerable<AccountEntity> GetAccountsInFriendlyFormat()
{
List<AccountEntity> accounts = new List<AccountEntity>();
using (dynamic WShell = AutomationFactory.CreateObject("WScript.Shell"))
{
for (int i = 1; i < 1000; i++)
{
try
{
string classId = WShell.RegRead(String.Format(registryPath, i.ToString().PadLeft(8, '0'), constValueClsid));
if (StringComparer.InvariantCultureIgnoreCase.Compare(classId, constContentsAccountClsid_POP3) == 0)
{
accounts.Add(new AccountEntity
{
FriendlyName = GetRegisterElementValue(WShell, i.ToString(), constAccountName),
IncomingMailServer = GetRegisterElementValue(WShell, i.ToString(), constPOP3Server),
Email = GetRegisterElementValue(WShell, i.ToString(), constEmail),
UserName = GetRegisterElementValue(WShell, i.ToString(), constName)
});
continue;
}
if (StringComparer.InvariantCultureIgnoreCase.Compare(classId, constContentsAccountClsid_IMAP) == 0)
{
accounts.Add(new AccountEntity
{
FriendlyName = GetRegisterElementValue(WShell, i.ToString(), constAccountName),
IncomingMailServer = GetRegisterElementValue(WShell, i.ToString(), constIMAPServer),
Email = GetRegisterElementValue(WShell, i.ToString(), constEmail),
UserName = GetRegisterElementValue(WShell, i.ToString(), constName)
});
continue;
}
//it isn't POP3 either IMAP
}
catch (FileNotFoundException e)
{
//classId isn't found - we can break iterations because we already iterate through all elements
break;
}
catch (Exception e)
{
MessageBox.Show("Unknown exception");
}
}
}
return accounts;
}
private string GetRegisterElementValue(object scriptShell, string elementNumber, string elementName)
{
dynamic shell = scriptShell;
string currentElement = elementNumber.PadLeft(8, '0');
object[] currentElementData = shell.RegRead(String.Format(registryPath, currentElement, elementName));
byte[] dataBytes = currentElementData.Cast<byte>().ToArray();
return Encoding.Unicode.GetString(dataBytes, 0, dataBytes.Count()).Trim('\0');
}
}
public class AccountEntity
{
public string FriendlyName { get; set; }
public string UserName { get; set; }
public string Email { get; set; }
public string AccountType { get; set; }
public string IncomingMailServer { get; set; }
}
主要技巧是使用 AutomationFactory.CreateObject("WScript.Shell")。现在可以使用 RegRead 方法直接从注册表获取帐户信息。顺便说一句,此代码甚至适用于 Outlook 2007/2010。对我来说,最好的方式是静默收集帐户(无需在数据收集之前启动 Outlook)。