DLL for VBA.Collection

2019-08-30 18:56发布

问题:

I need to use a VBA.Collection class and I need to register a COM component in order to do that. I found msvbvm60.dll file on my computer and successfully registered it in my system. I am creating an instance of a class VBA.Collection, but I get an exception in that line of code:

VBA.Collection collection = new VBA.Collection();

The exception has the following description:

System.Runtime.InteropServices.COMException was unhandled
HResult=-2147221164 Message=Retrieving the COM class factory for component with CLSID {A4C4671C-499F-101B-BB78-00AA00383CBB} failed due to the following error: 80040154 Class not registered (Exception from HRESULT: 0x80040154 (REGDB_E_CLASSNOTREG)). Source=mscorlib
ErrorCode=-2147221164

I used regedit.exe tool to search for a component with CLSID of {A4C4671C-499F-101B-BB78-00AA00383CBB}, but haven't been able to find one. I suspect that there should be another .dll file that I should register, even though I can see with Object Browser in Visual Studio that reference to msvbvm60.dll gives me access to VBA namespace and Collection class within it.

It says on this web-page http://codeverge.com/asp.net.migrating-from-asp/using-vba.collection-object-in-net/577432 that the problem will go away if I instantiate VBA.CollectionClass . However, if I do so, I receive the following error and my code doesn't compile:

Interop type 'VBA.CollectionClass' cannot be embedded. Use the applicable interface instead

Have I registered the wrong COM component? Or is there anything I need to change in my C# code?

I also read on How to create VBA.Collection() object in c# that I need to create my own class based on VBA._Collection interface and not instantiate VBA.Collection class. I created the following class:

class MyCollection : VBA._Collection
{
    private Dictionary<object, object> _items = new Dictionary<object, object>();

    public void Add(ref object Item, [System.Runtime.InteropServices.OptionalAttribute]ref object Key, [System.Runtime.InteropServices.OptionalAttribute]ref object Before, [System.Runtime.InteropServices.OptionalAttribute]ref object After)
    {
        // Ignoring the Before and After params for simplicity
        _items.Add(Key, Item);
    }

    public int Count()
    {
        return _items.Count;
    }

    public System.Collections.IEnumerator GetEnumerator()
    {
        return _items.Values.GetEnumerator();
    }

    public dynamic Item(ref object Index)
    {
        return _items[Index];
    }

    public void Remove(ref object Index)
    {
        _items.Remove(Index);
    }
}

I now instantiate MyCollection class with MyCollection collection = new MyCollection(); I do not get an exception there anymore. However, I need to call a method GetIncidentCodes() of another COM component that returns an object of type VBA.Collection. If I use collection = class1.GetIncidentCodes();, then my program won't compile because an explicit cast is required. If I use collection = (MyCollection) class1.GetIncidentCodes();, then I get the following exception:

Unable to cast COM object of type 'System.__ComObject' to class type 'PoliceDispatcherClient.MyCollection'. Instances of types that represent COM components cannot be cast to types that do not represent COM components; however they can be cast to interfaces as long as the underlying COM component supports QueryInterface calls for the IID of the interface.

Should I cast the return value of GetIncidentCodes() into interface VBA._Collection? I am new to .NET, so I am not sure how to do it.