已经与其基础RCW分离的COM对象无法使用 - 为什么会发生?

时间:2009-09-29 14:24:31

标签: c# .net com interop active-directory

我有时会遇到以下异常: 无法使用已与其基础RCW分离的COM对象

示例代码:

using (AdOrganizationalUnit organizationalUnit = new AdOrganizationalUnit(ADHelper.GetDirectoryEntry(ouAdDn))) 
{ 
using (AdUser user = organizationalUnit.AddUser(commonName)) 
{ 
//set some properties 
user.Properties[key].Add(value); 

user.CommitChanges(); 

user.SetPassword(password); //it is set using Invoke 

//must be set after creating user 
user.Properties["UserAccountControl"].Value = 512; 

user.CommitChanges(); 

} 
} 

AdUser看起来像这样:

public class AdUser : DirectoryEntry 
{ 
public AdUser(DirectoryEntry entry) 
: base(entry.NativeObject) 
{ 
} 

public bool SetPassword(string password) 
{ 
object result = this.Invoke("SetPassword", new object[] { password }); 
return true; 
} 
} 

这是我的代码的简化版本。有时会出现例外情况,有时则不会。大多数情况下,当我尝试设置UserAccountControl值时会发生这种情况。 有谁知道可能是什么原因?

我发现当我处理AdEser创建的DirectoryEntry并且我仍在尝试使用AdUser对象时会发生此错误。但是,上面发布的代码并非如此。 DirectoryEntry可能以某种方式处置自己吗?

当我尝试对许多活动目录对象执行操作时,我也会遇到此异常。例如,当我尝试为一千个用户设置SecurityDescriptor时,每200-300个用户就会收到此错误。当我在建立新连接后重试操作时,我不会得到例外。消息是检测到raceonrcwcleanup。我的应用程序不是多线程的。

任何帮助都将不胜感激。

2 个答案:

答案 0 :(得分:3)

是的,由于垃圾回收,可能会丢弃DirectoryEntry对象。 GC正在自己的线程中运行,因此可以在RCW清理上进行竞争。

尝试在AdUser对象中保存对它的引用。即它看起来应该是

public class AdUser : DirectoryEntry 
{ 
  DirectoryEntry entry;
    public AdUser(DirectoryEntry entry) : base(entry.NativeObject) 
    { 
      this.entry = entry;
    } 
    ...
}

答案 1 :(得分:2)

似乎问题是由AdUser中的NativeObject创建DirectoryEntry引起的。 当我从以下位置更改AdUser时:

public class AdUser : DirectoryEntry 
{ 
public AdUser(DirectoryEntry entry) 
: base(entry.NativeObject) 
{ 
} 
} 

创建了将DirectoryEntry视为组件的包装器:

public class ActiveDirectoryObject : IDisposable 
{ 
private bool disposed; 
public DirectoryEntry Entry { get; protected set; } 

public ActiveDirectoryObject(DirectoryEntry entry) 
{ 
Entry = entry; 
} 

public void CommitChanges() 
{ 
Entry.CommitChanges(); 
} 

public void Dispose() 
{ 
Dispose(true); 
GC.SuppressFinalize(this); 
} 

private void Dispose(bool disposing) 
{ 
if (!this.disposed) 
{ 
if (disposing) 
{ 
if (Entry != null) Entry.Dispose(); 
} 
disposed = true; 
} 
} 
} 

public class AdUser : ActiveDirectoryObject 
{ 
public AdUser(DirectoryEntry entry) 
: base(entry) 
{ 
} 
} 

然后我没有得到这些错误。 更多详情:http://directoryprogramming.net/forums/thread/7171.aspx