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.