无法使用已与其基础RCW分离的Outlook加载项::COM对象
虽然我发现这个问题有很多这样的例子,但我实施的任何解决方案都没有解决我的问题;希望你能帮我解开这个谜。注意:这是我第一次涉足COM对象的世界,所以我的无知既深又广 首先,我用的是阿德里安·布朗的。我不会完全复制他的无法使用已与其基础RCW分离的Outlook加载项::COM对象,com,outlook,outlook-addin,Com,Outlook,Outlook Addin,虽然我发现这个问题有很多这样的例子,但我实施的任何解决方案都没有解决我的问题;希望你能帮我解开这个谜。注意:这是我第一次涉足COM对象的世界,所以我的无知既深又广 首先,我用的是阿德里安·布朗的。我不会完全复制他的日历监视器类;以下是相关部分: public class CalendarMonitor { private ItemsEvents_ItemAddEventHandler itemAddEventHandler; public event EventHandler&l
日历监视器
类;以下是相关部分:
public class CalendarMonitor
{
private ItemsEvents_ItemAddEventHandler itemAddEventHandler;
public event EventHandler<EventArgs<AppointmentItem>> AppointmentAdded = delegate { };
public CalendarMonitor(Explorer explorer)
{
_calendarItems = new List<Items>();
HookupDefaultCalendarEvents(session);
}
private void HookupDefaultCalendarEvents(_NameSpace session)
{
var folder = session.GetDefaultFolder(OlDefaultFolders.olFolderCalendar);
if (folder == null) return;
try
{
HookupCalendarEvents(folder);
}
finally
{
Marshal.ReleaseComObject(folder);
folder = null;
}
}
private void HookupCalendarEvents(MAPIFolder calendarFolder)
{
var items = calendarFolder.Items;
_calendarItems.Add(items);
// Add listeners
itemAddEventHandler = new ItemsEvents_ItemAddEventHandler(CalendarItems_ItemAdd);
items.ItemAdd += itemAddEventHandler;
}
private void CalendarItems_ItemAdd(object obj)
{
var appointment = (obj as AppointmentItem);
if (appointment == null) return;
try
{
AppointmentAdded(this, new EventArgs<AppointmentItem>(appointment));
}
finally
{
Marshal.ReleaseComObject(appointment);
appointment = null;
}
}
这里抛出了一个错误,我试图向AppointmentItem添加一个UserProperty。我遵循了我能找到的最好的例子:
private void AddUserProperty(AppointmentItem item, string propertyName, object value)
{
UserProperties userProperties = null;
UserProperty userProperty = null;
try
{
userProperties = item.UserProperties;
userProperty = userProperties.Add(propertyName, OlUserPropertyType.olText);
userProperty.Value = value;
item.Save();
}
catch (Exception ex)
{
Debug.Print("Error setting User Properties:");
PrintToDebug(ex);
}
finally
{
if (userProperty != null) Marshal.ReleaseComObject(userProperty);
if (userProperties != null) Marshal.ReleaseComObject(userProperties);
userProperty = null;
userProperties = null;
}
}
。。。但当我尝试将UserProperty添加到AppointmentItem时,它会阻塞。我得到了一个经常出现的错误:
COM对象已经与其底层RCW分离,无法使用。
老实说,我不知道我在做什么;所以我正在拼命地为我的徒弟寻找一位绝地大师。这里的主要问题是使用Marshal.ReleaseComObject
来管理运行时在多个地方使用的RCW
事实上,这个代码引发了这个问题。让我们看看类日历监视器
:
private void CalendarItems_ItemAdd(object obj)
{
var appointment = (obj as AppointmentItem);
if (appointment == null) return;
try
{
AppointmentAdded(this, new EventArgs<AppointmentItem>(appointment));
}
finally
{
Marshal.ReleaseComObject(appointment);
然后,会附加一个
async
事件,该事件实际上会在使用约会
之前返回,就在等待
行:
private async void monitor_AppointmentAdded(object sender, EventArgs<AppointmentItem> e)
{
var item = e.Value;
Debug.Print("Outlook Appointment Added: {0}", item.GlobalAppointmentID);
try
{
var result = await GCalUtils.AddEventAsync(item);
看,它又在释放COM对象了。没问题,但根本不是最优的。这是使用ReleaseComObject
不知道发生了什么的一个指标,除非证明有必要,否则最好避免使用它
item = null;
}
}
本质上,
ReleaseComObject
的使用应经过以下几点的彻底审查:
- 我是否需要确保托管环境立即而不是在不确定的时间释放对象 有时,需要释放一些本机对象以引起相关的副作用 例如,在分布式事务下确保对象提交,但是如果您发现有必要这样做,那么您可能正在开发一个服务组件,并且没有在手动事务中正确登记对象 其他时候,无论每个对象有多小,您都在迭代一组庞大的对象,您可能需要释放它们,以避免应用程序或远程应用程序宕机。有时,GC’ing更常见,切换到64位和/或添加RAM以某种方式解决问题
- 从托管环境的角度来看,我是否是该对象的唯一所有者/指针 例如,该对象是我创建的,还是由我创建的另一个对象间接提供的 在托管环境中是否不再引用此对象或其容器
- 我是否明确地不在
之后、在其后的代码中或在任何其他时间使用对象(例如,确保不将其存储在字段或闭包中,甚至以迭代器方法或ReleaseComObject
异步
方法的形式) 这是为了避免可怕的断开连接的RCW异常
当您处理定期约会项目时,您应该释放所有以前的引用,在访问或修改该项目之前获取对定期约会项目的新引用,并在完成并保存更改后尽快释放这些引用。此实践适用于Recurrence AppointItem对象以及任何异常或RecurrencePattern对象。
-只是尝试遵循该指导。相信我。。所有这些Marshal.ReleaseComObject()
都不是我自己选择的。@HansPassant-我读了你非常优秀的帖子,但我还是有点模糊。您能从上面选择一个方法并正确地重新编写它作为答案吗?只需删除所有ReleaseComObject()调用。使用真实数据测试加载项时,请观察Outlook的内存使用情况。如果您真的有问题,那么只需计算操作数并以某个值调用GC.Collect()。这段代码并不重要。我的朋友,你需要重新发布这段代码作为答案,这样我才能接受它。删除所有的ReleaseComObject()
调用后,它不仅修复了这个问题,还修复了另一个问题。
private async void monitor_AppointmentAdded(object sender, EventArgs<AppointmentItem> e)
{
var item = e.Value;
Debug.Print("Outlook Appointment Added: {0}", item.GlobalAppointmentID);
try
{
var result = await GCalUtils.AddEventAsync(item);
//store a reference to the GCal Event for later.
AddUserProperty(item, Resources.GCalId, result.Id);
Debug.Print("GCal Appointment Added: {0}", result.Id);
}
catch (GoogleApiException ex)
{
PrintToDebug(ex);
}
finally
{
Marshal.ReleaseComObject(item);
item = null;
}
}