Search code examples
c#com

Creating instances of VpnApi COM object in Windows Service


I am using The Cisco AnyConnect VpnApi, I have created a COM 'Manifest?' dll that I am referencing in my service. I have also tried this just adding a reference to the COM service and letting VS embed the interop assembly. The service spins and does some stuff in the background waiting for a custom commend and kicks off the process in the ServiceBase.OnCustomCommand function. The service is running under the System account.

Using:

using VpnApiLib;

The code is pretty simple:

 IVpnApi vpn = null;
 try
 {
     vpn = new VpnApi();
     return true;
 }
 catch (Exception ex)
 {
     EventManager.PublishExceptionLogMessage(ex);
 }
 finally {
     if (vpn!= null)
         Marshal.ReleaseComObject(vpn);
 }
 return false;

However when this is called from the service I get an AccessViolationException:

"Attempted to read or write protected memory. This is often an indication that other memory is corrupt."

My Stack Trace:

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

At one point I got a different exception: "Retrieving the COM class factory for component with CLSID {C15C0F4F-DDFB-4591-AD53-C9A71C9C15C0} failed due to the following error: 800701e7.

So I tried putting this code and referencing the COM object in a Console app and it resolves just fine with no exceptions.

I have tried every possible thing I can think if, including impersonation using some tested and woring pinvoke code that I have. Nothing seems to work, whenever this is called from the windows service I get one of these exceptions.


Solution

  • So I finally figured it out after spinning my wheels on this for 3 days.

    The problem was that the the COM object was actually being referenced in another class the 'bootstrapper' of the application (which I inherited) and was being indirectly loaded via Unity via an assembly search pattern which was obscuring the problem somewhat.

    The root of the issue stems from the behavior of COM objects loaded in memory. Apparently when referenced through the surrogate (generated by tlbimp.exe), the COM object itself is loaded into a fixed location in memory which is then stored in the surrogate when it is instantiated. The simple fact of it being referenced in the boot strapper and being loaded via unity created the instance in memory on the main thread.

    When the OnCustomCommand event was being fired it was coming back on a different thread when apparently didn't have access to the memory where the main thread loaded the COM object. Hence the "protected memory" error.

    That said, the class that was referencing this was not in use so I just commented it out and everything started working. However, I think the eventual solution to this will be some sort of proxy class for all access to the VpnApi COM object which either has a scheduler that directs to a single thread or maybe some sort of singleton class.

    Not sure yet, I haven't given it a lot of thought. Once I figured out, I just dropped the mic and went home! lol If any of you have any suggestions, you would certainly get my up-votes.