Monday, April 17, 2006

Building Upgrade-Safe Add-ins for MindManager

April 17,2006 Mindjet has updated all its addins to use a signed Primary Interop Assembly (PIA). This follows Microsoft best practice, and we strongly encourage all .Net developers that build integrations with MindManager to follow suite.

In this article I have tried to answer the need for PIA, the problem it causes, how to create addins in MindManager referencing PIA and how to update the addins to use PIA.

You can download Mindjet signed MindManager PIA from http://www.mindjet.com/us/devzone/6/PIA

What is PIA and why do we need PIA (Primary Interop Assembly)
MSDN has explained it on http://msdn.microsoft.com/library/default.asp?url=/library/en-us/dndotnet/html/whypriinterop.asp

How all this works, currently, and what is the problem?

How the COM and .NET communicates:
.NET CLR creates something called as Runtime callable wrapper (RCW) and this is what is used by .NET code to communicate with COM server, its primary function is to marshal calls between a .NET client and a COM object. In our case .net client is our Addin and COM object is MindManager.

In current scenario:
When you create an addin using Visual Studio and add a reference to MindManager Type Library, VS creates an Interop assembly (IA) (if PIA is not registered). So let us say that you created an addin with an older version of MindManager and then you installed a newer version of MindManager and built another addin. At this time there are two different versions of IA that each of these addins use when they load in MindManager. Now when you start MindManager it loads an addin and tries to load another one, since both the addins were NOT built using PIA they load their respective IA’s from their application folder.

Now the problem:
Here is what we need to know, when the first addin loads it creates a RCW (let us name it RCW1) for itself and when the second addin loads (and since this also does not uses a PIA) it creates another RCW (alias RCW2) for itself. So we get two RCWs whereas, at any time, there should NOT be more than one RCW for one application. The reason why we need only one RCW is: once you modify a COM object in first RCW the updated metadata would not be visible to second RCW.
For e.g. you modify the applications (MindManager’s) commands object collection in first addin (or using the RCW1) and then in your second addin you loop over the commands collection at this time the RCW will know that there is something changed in the commands object but what has changed it (RCW2) wont not know because the metadata for the modified object is not visible to RCW2 at this time, therefore CLR throws an invalid cast exception (“Specified cast is not valid”) or “Query Interface for .. failed

How to build new addins?
We need to make sure that we have only one RCW at any given time for all the addins that we load. To achieve this you need to make sure that you have only Mindjet signed (strong named) MindManager Interop (Mindjet.MindManager.Interop.dll) in the GAC (global assembly cache) and is registered.
It is strongly recommended that you use
Mindjet MindManager PIA redistributable merge module with all your addins so as to make sure that the Interop is available in the GAC and if a newer version is required the installer for your addin automatically installs it.
Once you have the required files in the GAC and registered, you do not need to do anything different from what you have been doing. Open VS and create an addin and add a reference to MindManager type library at this time VS silently use the registered PIA instead of re-importing the type library.

To create an addin you can use
Mindjet’s Visual Studio Project Template for C# and VB Add-Ins that takes care of these things automatically but you would still need to

Click here to download the
Mindjet MindManager PIA redistributable. This installer installs MindManager PIA (Mindjet.MindManager.Interop.dll) in the GAC and installs a merge module in your %Programfiles%/Common Files/Merge Modules/ MindManagerredist_>version<.msm While building new addins make sure that there is no local copy of PIA. If Addin setup project has Mindjet.MindManager.Interop.dll as the dependent file, make sure that it is excluded.


Will it affect the current addins?
Yes, it might affect you current addins.

How to update current addins?
--> Get the latest installer for Mindjet MindManager PIA redistributable from Mindjet’s devzone website. Install it.
--> Open your addin project. Remove existing reference to MindManager. Now add the reference to MindManager again.
--> Now compile your project you will get the namespace errors. You need to change the namespace from “MindManager” to “Mindjet.MindManager.Interop”
--> Build your project again. At this time, in your setup project, you might see that there is an added dependency for “mindmanagerredist_>version<.msm”. This is a Mindjet’s redistributable merge module, to ensure that when you distribute your addin if the user has an older version of PIA it updates the older version with the version that you used to build the addin. If they have a newer version of the PIA installed the merge module does not change anything. If you don’t see this added then right click on your setup project (in solution explorer in VS) and then select Add Merge Module and select from %Programfiles%/Common Files/Merge Modules/ MindManagerredist_>version<.msm

Remember:
--> Make sure that you have installed the latest PIA Redistributable on your computer. It will make sure that you have the latest PIA and the merge module for backward compatibility.
--> While building addins make sure that Mindjet.MindManager.Interop.dll is not copied locally.
--> Make sure that you include the MindManagerredist_>version<.msm in your addin’s setup.

Vivek Vishist

http://labs.mindjet.com