Legacy in Visual Studio: GUID's for COM Interop in Excel. Why?
Ingredients
- Visual Studio 2015 or 2017
- A Class you want to expose through COM
Background
Back in the late 80's and early 90's, OS vendors & language creators were considering the problem of linking, loading and runnning external, common code libraries and interprocess communication (IPC) between applications that went beyond static object files. Whilst Unix & then Linux went down the route of Shared Object libraries (.so extensions), pipes (named or anonymous) and sockets, Microsoft chose to use their Dynamic Link Libraries or DLLs as the natural progression from the Windows API into more mainstream shared library files. You would initially call them by static or dynamic linking of these libraries together with your executable, then calling the functions held within them. This was distinct from the old Dynamic Data Exchange mechanisms which were just the way applications themselves sent messages to other applications using Windows Messages in the Windows Message loop (if you don't know what that is, just take my word for it. Unless you have a desperate need to die of boredom whilst I explain Windows API programming ).
Over time DLL's evolved to become a kind of "catch all" library, as Microsoft sawit as a good idea to extend DLL's to create the Component Object Model (COM) and it's middleware products Microsoft Transaction Services (MTS) which later became COM+. Both built on top of Distributed-COM (DCOM), a mechanism of calling remote code in exactly the same, transparent way as COM objects. Largely, it worked fine.
To do that, Microsoft needed a single place to store indices or references to these reusable components and libraries. They chose the Windows Registry. Specifically, the HKEY_CLASSES_ROOT registry key.
The registry stores Interface Identifiers and Object Identifiers as UUID (aka GUID) or Universally Unique Identifiers and using both the system time and identifiers on the generating machine, including its MAC address, as part of a hash, ensures that no two GUID's are ever likely to be the same. UUID's are not a Windows invention. They were created by NCS and later, DCE organisations. There is even a standard (RFC4122) which defines them.
Important Note
Note, don't work with the Windows Registry unless you really know what you're doing. As well as being the central reference for all COM libraries, it also contains a multitude of other switches for Windows itself. The registry is Windows' achilles heel. If it becomes corrupted, windows simply stops working. As a result, it is a prime target for hackers and Ransomware programmers, since you can lock down an entire system from there. But you haven't heard that from me and I sure as heck won't be posting bail if you get yourselves in trouble with the law
COM: Seperate Interface and Object Code
COM works by looking up objects that implement particular interfaces, defined by thes GUIDs, then invoking them. Like IDisposable in .NET, there is an internal reference counter that disposed of the object when the reference count hits zero and equally, spins it up when the first COM object instance is invoked, incrementing the reference counter as it does so. The interface and objects are different, but at the same time, they are linked. In addition, COM allows you to expose what are called "Dispatch Interfaces" which then expose the OLE Automation interfaces that VBA is more naturally inclined to use.
Back to the Future
These days, we've moved quite a way past COM, DCOM and COM+. Yet, despite this, there are still a tonne of unmanaged, legacy usages out there, whether we want to consume them in .NET or expose them from .NET when interfacing .NET managed code with Microsoft Office VBA, Java-COM bridges (JACOB) or even scripting through VBS.
Recently, there was a call to interface Excel with .NET. Something I've had to do in managed and unmanaged code environments for nearly 20 years. There are a lot of pitfalls, not least due to the Marshalling of objects through COM Interop and from one process to a .NET DLL. The most recent editions of the .NET Framework and Visual Studio, make that process a lot easier hasn it used to be! But you are still limited to the use of GUID's for the identification of the exposed .NET/C#/VB.Net classes in the Registry, so VBA and other environments can be found through OLE Automation or straight COM invocation.
In order to link VBA to .NET's objects in VS2017, we have to expose the classes as COM objects and make that library accessible through COM.
Step 1: Generate a GUID
The first part of that is to generate GUID's for the COM interfaces and their Object Implementations. To do that, you can use an online GUID generator or better still, Visual Studio's built in GUID generator from the menu 'Tools>Create Guid'.
Step 2: Apply the GUID
To apply the GUID's to the objects and interfaces you want to expose through COM in C#.
- Select option 5 in the resulting dialog box.
- Click the Copy button and paste it onto the class or interface declaration you want to expose.
Step 3: Rinse and Repeat for the Implementation Class
Do the same for the Implementing class and you're ready to move on to the next stage of the setup.
Next Steps
After you've done this, you need to set the library to expose COM objects. I'll cover this another day if there is enough interest. So hit like if you'd like to see an example, a link to a sample GitHub repo or if you just liked the article. If you have a COM interop project you need help with, hit me up.
For now, happy coding!