C# 在Windows服务中创建VpnApi COM对象的实例

C# 在Windows服务中创建VpnApi COM对象的实例,c#,com,C#,Com,我正在使用Cisco AnyConnect VpnApi,我已经创建了一个COM“清单?”dll,我正在我的服务中引用它。我也尝试过这样做,只是添加对COM服务的引用,并让VS嵌入互操作程序集。该服务在后台旋转并执行一些操作,等待自定义命令,并在ServiceBase.OnCustomCommand函数中启动该过程。服务正在系统帐户下运行 使用: using VpnApiLib; 代码非常简单: IVpnApi vpn = null; try { vpn = new VpnAp

我正在使用Cisco AnyConnect VpnApi,我已经创建了一个COM“清单?”dll,我正在我的服务中引用它。我也尝试过这样做,只是添加对COM服务的引用,并让VS嵌入互操作程序集。该服务在后台旋转并执行一些操作,等待自定义命令,并在ServiceBase.OnCustomCommand函数中启动该过程。服务正在系统帐户下运行

使用:

using VpnApiLib;
代码非常简单:

 IVpnApi vpn = null;
 try
 {
     vpn = new VpnApi();
     return true;
 }
 catch (Exception ex)
 {
     EventManager.PublishExceptionLogMessage(ex);
 }
 finally {
     if (vpn!= null)
         Marshal.ReleaseComObject(vpn);
 }
 return false;
但是,当从服务调用时,我会得到一个AccessViolationException:

“试图读取或写入受保护的内存。这通常表示其他内存已损坏。”

我的堆栈跟踪:

at System.RuntimeTypeHandle.CreateInstance(RuntimeType type, Boolean publicOnly, Boolean noCheck, Boolean& canBeCached, RuntimeMethodHandleInternal& ctor, Boolean& bNeedSecurityCheck)
at System.RuntimeType.CreateInstanceSlow(Boolean publicOnly, Boolean skipCheckThis, Boolean fillCache, StackCrawlMark& stackMark)
at System.RuntimeType.CreateInstanceDefaultCtor(Boolean publicOnly, Boolean skipCheckThis, Boolean fillCache, StackCrawlMark& stackMark)
at System.Activator.CreateInstance(Type type, Boolean nonPublic)
at System.Activator.CreateInstance(Type type)
at ...ConnectivityAction.IsVpnInstalled() in D:\...\ConnectivityAction.cs:line 208
有一次我遇到了另一个例外: 由于以下错误,检索CLSID为{C15C0F4F-DDFB-4591-AD53-C9A71C9C15C0}的组件的COM类工厂失败:800701e7

因此,我尝试将此代码和引用COM对象放在控制台应用程序中,它可以很好地解决问题,没有任何异常


我已经尝试了我能想到的所有可能的事情,包括使用我拥有的一些经过测试和正在编写的pinvoke代码进行模拟。似乎什么都不起作用,每当从windows服务调用时,我都会遇到这些异常。

像这样的错误有时会因为链接问题而发生,本论坛的帖子似乎表明这是一个错误在这里可能是这样的:


所以我在这上面转了3天的轮子,终于找到了答案

问题是COM对象实际上是在应用程序的另一个类“bootstrapper”中引用的(我继承了这个类),并且是通过Unity通过一个汇编搜索模式间接加载的,这在某种程度上掩盖了问题

问题的根源在于加载到内存中的COM对象的行为。当通过代理引用(由tlbimp.exe生成)时,显然,COM对象本身被加载到内存中的固定位置,然后在实例化时存储在代理中。简单的事实是,它在引导程序中被引用,并通过unity加载,从而在主线程的内存中创建了实例

当OnCustomCommand事件被触发时,它返回到另一个线程上,而该线程显然无法访问主线程加载COM对象的内存。因此出现了“受保护内存”错误

这就是说,引用它的类没有被使用,所以我只是注释掉了它,一切都开始工作了。然而,我认为最终的解决方案将是某种代理类,用于所有对VpnApi COM对象的访问,它要么有一个指向单个线程的调度程序,要么可能是某种单例类


还不确定,我还没想太多。一旦我想明白了,我就放下话筒回家了!哈哈,如果你们有任何建议,你肯定会得到我的支持票。

你能试着用
LoadLibrary
方法来代替吗?和@HansPassant一样是的,类似的问题,但在我的情况下答案完全不同。我事实上,我确实在这里发现了这个问题,就像思科论坛上的另一篇帖子一样,它把我引向了错误的方向。然而,我昨天晚上确实弄明白了,答案发布在下面。关于COM对象和内存的一些有趣的信息可能对遇到同样问题的任何人都有用。嗯,还不确定,我有我没怎么考虑。听起来像是线程问题,总是要确保创建COM对象的线程在对象不再使用之前不会终止。这是一个在服务中特别容易违反的要求。是的,这正是正在发生的事情。:)是的,我找到了那篇文章。这篇文章实际上让我很失望试图用LoadLibrary实现这一点的漫长道路。这让我花了两天的时间,最终找到了一个相反的解决方案,我将把它作为我自己问题的答案发布。