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

时间:2016-01-13 21:12:34

标签: c# com

我正在使用Cisco AnyConnect VpnApi,我创建了一个COM' Manifest?'我在我的服务中引用的dll。我也试过这个只是添加对COM服务的引用并让VS嵌入interop程序集。该服务在后台旋转并执行一些操作,等待自定义命令并在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服务调用,我都会得到其中一个例外。

2 个答案:

答案 0 :(得分:1)

这些错误有时会因为链接问题而发生,而这个论坛帖子似乎暗示这可能是这种情况:

https://supportforums.cisco.com/discussion/12188291/c-new-vpnapiclass-get-com-exception-800701e7-till-reboot

答案 1 :(得分:0)

所以我终于在将轮子旋转3天之后弄明白了。

问题是COM对象实际上是在另一个类中被引用的' bootstrapper'应用程序(我继承)并通过汇编搜索模式通过Unity间接加载,这有点模糊了问题。

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

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

也就是说,引用它的类没有被使用,所以我只是评论它并且一切都开始工作了。但是,我认为对此的最终解决方案将是某种代理类,用于对VpnApi COM对象的所有访问,该对象具有指向单个线程或可能某种单例类的调度程序。

还不确定,我还没有多想过。一旦我弄明白,我就放下麦克风回家了!大声笑如果你们有任何建议,你肯定会得到我的投票。