(Cross-posted on the Corepoint Health community site.)
Update, March 6, 2015: These directions were written for Corepoint 5.2.x. Updated directions for Corepoint 6.0 are available on the Corepoint Health community site, linked above.
I need to hash a string in Corepoint, but it doesn’t seem to have any hashing functionality built in. An easy way to do this is to call a stored procedure to have the database do the hashing. This works fine, except for that SQL Server will toss an error if the length of the string being hashed is more than 8000 characters. To hash an arbitrarily long string, using Corepoint’s ItemInvoke action to call external code seemed like a reasonable next step.
Corepoint’s ItemInvoke allows you to call code stored in a COM object. I’ve done a fair bit of software development but I can’t say I’ve ever been asked to write a COM object. I needed to learn how to write a COM object, and more specifically, how to do it in such a way that it will work with Corepoint.
I searched the documentation and the community site for information to get me started. Corepoint’s documentation has about the bare minimum that you would need to pull this off and assumes some degree of familiarity with COM objects. On the community site, I found some mentions of things like, “Hey, I found this COM object that does such-and-such-a-thing,” but not much on actually creating them. So, I thought I would put together a “Getting started with COM objects in Corepoint” tutorial, the target audience being people who have experience with software development and just need to figure out the part where you need to get Corepoint and your code talking.
It’s possible to write COM objects in a number of different languages. I’m using C# for this tutorial. If you are interested in using a different language, there still may be bits of information here that will be helpful to you.
You will need installed…
- Corepoint Integration Engine
- Microsoft Visual Studio
- Microsoft GUID Generator, aka guidgen.exe
- sn.exe (you probably already have it — details below)
- regasm.exe (you probably already have it — details below)
I’m also assuming that you have some basic knowledge of the Corepoint Integration Engine, Visual Studio, finding files on your system, using the command line, interpreting error messages, and so forth.
Let’s get started.
I will begin by explaining how to build an “empty” COM object in Visual Studio. This COM object will show up available for use in Corepoint but not do anything. Following these steps will allow you to make sure that you have the build environment set up properly, and make sure that Corepoint can see your COM object. After this is done, I will explain how to get information from Corepoint to your object and vice versa.
In my case, I’m using Visual Studio 2013 (“Express for Windows Desktop” version), which is available for free. The procedure should be the same for Visual Studio Professional (or better), but the screens and menus may be slightly different if you are using a version other than 2013. I’m targeting version 5.2.4 of the Corepoint Integration Engine, but I don’t have any reason to believe that the COM object functionality in Corepoint changes much from version to version.
You will need to run Visual Studio “as administrator.” Later on when we have Visual Studio automatically register the COM object, it will need administrative privileges during the build process to do this.
Start out by creating a new “Class Library” C# project in Visual Studio.
This will create a new project with two code files, AssemblyInfo.cs and Class1.cs. Class1.cs contains a class named Class1. You can rename the class to anything you like. Right-click the Class1.cs file in the Solution Explorer and rename it from there (it will update the class name for you).
Give your class a public constructor with no parameters. (It does not need to do anything, but it needs to be present.)
You will need to add the Corepoint COM object interface to your project. This interface lives in the Corepoint-provided file, Invoke.dll. The Corepoint documentation says that this file can be found in C:\Program Files (x86)\Corepoint Health\Gears\RFMDB\, but I wasn’t able to find it there. I found it instead in C:\Program Files (x86)\Corepoint Health\Shared Components\. In the Visual Studio solution explorer, right-click on “References”, choose “Add Reference…”, go down to the “Browse” tab on the left, click the “Browse” button and locate “Invoke.dll“. Check the box and click “OK” to bring it in to your project. It will show up as “INVOKELib.”
Add these lines to the top of your class file to bring in the functionality that we need for Corepoint COM:
using System.Runtime.InteropServices; using INVOKELib;
The class needs to implement the corepoint “IInvoke” interface, which lives in the Invoke.dll file that we added to the project. Add “ : IInvoke” to your class definition. Then, right-click the “IInvoke” text and select “Implement Interface -> Implement Interface” from the menu. Visual Studio will fill in the method that needs to be implemented, which has four string parameters defined by Corepoint.
public void Invoke(ref string SourceArgument, ref string Options, ref string ResultData, ref string Error)
This method is what you will actually call using ItemInvoke in Corepoint. I’ll explain more about the parameters in a bit. For now, let’s finish getting the COM object set up.
At this point, your code should cleanly build, so you might want to check that. If there are any errors, you will want to address them before moving on.
The “Invoke” method comes with single line that just throws an exception. I’m going to go ahead and remove this line so that the method is empty. Otherwise, we’ll get an error when we try to call it from Corepoint in a bit.
Each COM object needs a globally unique ID. We will use the Microsoft GUID Generator (guidgen.exe) to generate a GUID. Run the generator, select “Registry format” for the GUID format, and then click the button for “New GUID”. Now that one has been generated, you may use the “Copy” button to get it in the clipboard. In Visual Studio, you will need to add the GUID above the class definition, like this:
[Guid("1E2D6FC4-BB88-41e5-A8DE-2A475968E2AD")] public class CorepointCom : IInvoke { ... }
Each COM object needs a “strong name”, which gives it a unique signature. (I tried skipping this step and ran into problems accessing the COM object after it was registered.) To handle this, you will first need to create a cryptographic key pair to sign the object. You can do this using the sn.exe tool, included with the .NET SDK. Since you have Visual Studio installed, you probably already have a copy of the .NET SDK. I the tool in this location: C:\Program Files (x86)\Microsoft SDKs\Windows\v8.1A\bin\NETFX 4.5.1 Tools\. If you can’t find it, you can download a copy of the .NET SDK from here.
Anyway, a command like this to create your key pair:
sn -k CorepointCom.snk
Move the .snk file into your Visual Studio project folder, and then add it to your project using “Project -> Add Existing Item…” (change the drop down to show “All Files” if you can’t see it). Open the project properties using “Project -> [project name] Properties…”. Go to the “Signing” tab on the left. Check the box “Sign the assembly”, and select your key pair from the drop-down.
While we’re in the project properties area, let’s take care of a few other things. Go to the “Application” tab on the left, and choose the framework version that you’d like to target from the “Target framework” drop-down. (This version of the framework will need to be installed wherever you plan on deploying this object.) Click on the “Assembly Information” button, check the box for “Make assembly COM-Visible”, and click “OK”. Then go to the “Build” tab on the left, and check the box for “Register for COM interop”. Do this for both the “Debug” and “Release” build profiles.
Save the project and try building it again. It should succeed with no errors. (If you get an error about registering the COM object, make sure you are running Visual Studio “as administrator” as I mentioned above.)
So, now your COM object is built and registered, even though it does not have any functionality. However, we’re not quite done. Before Corepoint will let us use it, it must be registered with the category identifier (CATID) provided by them. We can write some code to be executed when the object is registered to handle this. Add these two methods to your class:
); }
740B2584-57D6-46CB-A85D-B2D255115A97 is the category identifier provided by Corepoint. This code will add a registry key that adds the COM object to the category when it is registered (and also clean itself up after itself if the object is unregistered). Corepoint looks for objects in this category when displaying objects available for use with ItemInvoke.
Build your project again. As before, it should go without errors.
Now… The COM object is built, implements the proper interface, and is registered using the proper category identifier… It should show up available for use up Corepoint ItemInvoke dialog.
Great. Now, how do we actually do something?
Looking at the method definition for “Invoke“, which comes from the “IInvoke” interface provided by Corepoint, we four parameters…
public void Invoke(ref string SourceArgument, ref string Options, ref string ResultData, ref string Error)
They are all strings passed by reference. Two of them are actually “input” parameters, and two are “output” parameters. For the input parameters, the “Source Operand” and “Object Options” fields in the Corepoint ItemInvoke dialog map to the “SourceArgument” and “Options” parameters respectively. In the ItemInvoke dialog, you must set the “Destination Operand” and “Status Variable”, which will be filled in by values set to the “ResultData” and “Error” parameters in the COM object.
Here, I am filling in some values to the ItemInvoke dialog that can be used as a simple illustration of the behavior of our COM object.
Here you can see the resulting line in the Corepoint action list, as well as a couple more lines that I’ve added to capture the COM object output.
Testing this simple action list, here is the output:
(If you see an error message that states that the method is not implemented, make sure that you took out the “throw new NotImplementedException();” line in the COM object’s “Invoke” method.)
Obviously, the “Result” and “Status” values are not filled in, as the COM object currently does nothing. Let’s add some code to demonstrate that it works as expected. Here is my implementation of the “Invoke” method:
public void Invoke(ref string SourceArgument, ref string Options, ref string ResultData, ref string Error) { if (SourceArgument == "Expected Source") { ResultData = "Expected Result"; } else { ResultData = "Unexpected Result"; } if (Options == "Expected Options") { Error = "Expected Status"; } else { Error = "Unexpected Status"; } }
Here, we are checking to see that the expected values came in for “SourceArgument” and “Options“, and depending on this condition, placing one of two strings in the “ResultData” and “Error” parameters.
Note — After calling the COM object once from Corepoint, if you want to make a change and rebuild it in Visual Studio, you may have to close the Corepoint Integration Engine Configuration application. Otherwise, it will hold a lock on the COM object DLL, and Visual Studio will throw an error when it tries to rebuild it. Also, if the Corepoint Integration Engine background service has executed an ItemInvoke command, it may need to be stopped before you will be able to rebuild COM object.
Now, after rebuilding and testing with Corepoint again:
We can see that the values in the “Result” and “Status” variables in Corepoint reflect that the expected values made it into the COM object.
From here, you should be able to take anything that you can pull off in C# and use it in a Corepoint action list, as long as you can deal with the “two strings in, two strings out” condition enforced by the COM object interface.
Your COM object will not be versioned in Corepoint and you will need to manually copy the DLL (which you can find in the “bin” folder of your Visual Studio project) when you need to deploy your Corepoint configuration to another machine. The DLL must be registered on each machine that needs to use the COM object. You don’t need Visual Studio installed on each target machine, but you do need the appropriate version of the .NET framework.
You can register the DLL with a command like this:
regasm CorepointComTest.dll /codebase /tlb /nologo
regasm.exe can be found in C:\Windows\Microsoft.NET\Framework\[version]\. If you can’t find it, make sure that you have the .NET framework installed.
These resources helped me pull this off:
- Corepoint documentation
- This blog post
- This article
- This Q&A
Below, I’ve listed the full contents of the COM object class file used in this tutorial:
using System; using System.Collections.Generic; using System.Linq; using System.Text; using System.Threading.Tasks; using System.Runtime.InteropServices; using INVOKELib; namespace CorepointComTest { [Guid("1E2D6FC4-BB88-41e5-A8DE-2A475968E2AD")] public class CorepointCom : IInvoke { public CorepointCom() { } public void Invoke(ref string SourceArgument, ref string Options, ref string ResultData, ref string Error) { if (SourceArgument == "Expected Source") { ResultData = "Expected Result"; } else { ResultData = "Unexpected Result"; } if (Options == "Expected Options") { Error = "Expected Status"; } else { Error = "Unexpected Status"; } } ); } } }