I am the author of the DXCore plugin "CR_Documentor." As part of the plugin, under DXCore 3.0.8.0, I had an implementation of the DevExpress.CodeRush.Common.ProductModule so the plugin information and logo would appear in the "About" box.
The interface for the ProductModule class changed in version 9.1.2.0 and simply implementing [what appears to be] the correct changes for the interface don't allow my information to appear in the "About" box.
I have marked my assembly with the following attributes:
[assembly: DXCoreAssembly(DXCoreAssemblyType.PlugIn, "CR_Documentor")]
[assembly: DXCoreProduct(typeof(CR_Documentor.CR_DocumentorProductModule))]
[assembly: DXCoreAuthorizedAssembly(LoadAuthorization.AllProducts)]
The use of the DXCoreAuthorizedAssemblyAttribute is a guess on my part; it appears to be there in all of the working assemblies that properly display product module information. The other two items remain unchanged from the 3.0.8.0 engine implementation and seem to be the same in the latest version.
I have a class that derives from ProductModule as noted in the DXCoreProductAttribute declaration above. For the 9.1.2.0 engine I've had to add an empty "BuildDefenition" method override as well as a getter for a ModuleType property which I have set to return ModuleTypes.Free (it's a free product).
Unfortunately, this doesn't seem to be enough. I have tried strong naming/signing my plugin assembly since Reflector shows me that there's something around the "plugin key" in the ProductManager class but that didn't fix anything and I noticed other successful implementations of the ProductModule don't seem to deal with that anyway.
What are the steps I need to take to get the ProductModule working? I need to get this fixed so I can release a version that works with the latest DXCore.
We have closed this ticket because another page addresses its subject:
Loader Engine - Product modules defined inside plugins are not loaded to the DXCore product manager
Hi Travis,
Actually, you should create two libraries: one for a plug-in and one for a module. Here are the detailed steps:
protected override void BuildDefenition() { DefinePlugIn("SyncXPOClassInvoker.dll"); }
[assembly: DXCoreProduct(typeof(TestProductModule.TestModule))] [assembly: DXCoreAssembly(DXCoreAssemblyType.PlugIn, "Test DXCore Module")] [assembly: DXCoreAuthorizedAssembly(LoadAuthorization.AllProducts)]
[assembly: DXCoreAssembly(DXCoreAssemblyType.PlugIn, "SyncXPOClassInvoker", PlugInLoadType.Demand, "490206186df575cf")]
%ProgramFiles%\DevExpress 2009.1\IDETools\System\DXCore\BIN\Modules
After that, you module should be loaded.
Attached is a sample module, as well as a sample plug-in. Hopefully, they will be of some help.
Thanks,
Vito
So it appears that there are two big changes here from the DXCore 3.0.8 version:
The first item is really disappointing - in 3.0.8 I could do this all in one assembly. Is there really no way to do it all in one assembly?
The second item is also disappointing - I didn't want to have to sign the thing, and now I'll end up having to deal with that in an open source capacity.
Is there any thought to moving this back to a simpler method of implementation the way it was in 3.0.8? These new restrictions seem fairly limiting.
Since I want an easier deployment and development experience - one assembly to drop in a folder, no keys to manage - I will probably end up dropping this functionality, which is unfortunate. It was nice to have the convenience of showing in the "About" box.
Please let me know if there's an easier way to do this.
Is there a way I can dynamically generate the product module assembly in memory and register it rather than having to have a physical assembly?
Does everything really need to be signed?
I am working with the example and the product module does get loaded (the key seems to be that it has to be in that "Modules" folder, which is the biggest change) but looking at the list of plugins in the Plugin Manager, the demo plugin (which I've placed in the Community/PlugIns folder) was not loaded.
It also turns out that you don't have to sign the ProductModule assembly OR the plugin assembly in order for it to show up in the About box, which is nice.
That said, if the ProductModule assembly was signed, the plugin wouldn't be loaded unless it was in the C:\Program Files\DevExpress 2009.1\IDETools\System\DXCore\BIN\PLUGINS folder folder. Once I stopped signing the ProductModule assembly I was able to put the plugin in the Community\PlugIns folder and it worked correctly.
So I guess my question boils down to:
* Can I programmatically register my own ProductModule so I don't have to have a separate assembly in the Modules folder?
OR
* Can I somehow get a plugin to register if I put it in the Modules folder?
I think I've figured it out, but you're not going to like it.
Well, probably not.
First, I changed the product module assembly to be a plugin that loads at startup:
[assembly: DXCoreAssembly(DXCoreAssemblyType.PlugIn, "Test DXCore Module", PlugInLoadType.StartUp)]
The ugly part is that I could add a new StandardPlugIn that does some reflection in the InitializePlugIn method to mimic what happens at app startup time with the ProductManager initialization.
using System;
using System.Collections;
using System.Reflection;
using DevExpress.CodeRush.Common;
using DevExpress.CodeRush.PlugInCore;
namespace TestProductModule
{
public partial class ProductRegistrationPlugIn : StandardPlugIn
{
public override void InitializePlugIn()
{
base.InitializePlugIn();
DXCoreProductAttribute attrib = typeof(ProductRegistrationPlugIn).Assembly.GetCustomAttributes(typeof(DXCoreProductAttribute), false)[0] as DXCoreProductAttribute;
ProductModule productModule = attrib.CreateModule();
DXCoreProduct product = null;
ConstructorInfo ctor = typeof(DXCoreProduct).GetConstructor(BindingFlags.Instance | BindingFlags.NonPublic, null, new Type[] { typeof(ProductModule) }, null);
product = (DXCoreProduct)ctor.Invoke(new object[] { productModule });
IList productModuleList = typeof(ProductManager).GetField("_ProductsModules", BindingFlags.NonPublic | BindingFlags.Static | BindingFlags.GetField).GetValue(null) as IList;
productModuleList.Add(productModule);
IList productList = typeof(ProductManager).GetField("_Products", BindingFlags.NonPublic | BindingFlags.Static | BindingFlags.GetField).GetValue(null) as IList;
productList.Add(product);
}
public override void FinalizePlugIn()
{
base.FinalizePlugIn();
}
}
}
It was ugly primarily because I wasn't able to get anything into the list of Products or Product Modules after the ProductManager.Initialize method was already called. Also, the constructor for DXCoreProduct is internal. Even calling ProductManager.Register didn't get it in there because Initialize had already been called and it appears that calling it twice will register everything again that's already been registered. Not good.
I did notice that the DevExpress.DXCore.Loader.LoaderEngine constructor reads some ProductModule paths from decoupled storage. Unfortunately, I run into a chicken-and-egg situation there because my plugin won't already have been loaded by the time the options are run so even if I poked the path in on registration it won't pick it up until the second execution of Visual Studio.
I suppose all of this (multiple assemblies, etc.) becomes moot if I make an installer, but a primary goal is XCopy deployment.
*** Can I get a public interface to registering a product module so I don't have to do this reflection nonsense? ***
If so, I will release a version of my plugin without a product module for the 9.1.2 engine and then will put the product module back in place when the public interface is released. If not… I may just chance the reflection magic because I feel like the polish of having a product module and appearing in the "About" box is a nice touch.
Hi Travis,
Our developers have made several changes, and a product module, defined in the plug-in's assembly (e.g. please look at the attached sample) should now be loaded correctly. Please look at the following bug report:
ID: B36747, Loader Engine - Product modules defined inside plugins are not loaded to the DXCore product manager
These changes will be included in the next product version. If it is a matter of urgency for you, you can click the "Request Fix" button. We'll publish the corresponding daily build, containing the necessary changes.
Thanks,
Vito
PERFECT! Thanks!
Question answered. I'll request the fix and verify the fixed functionality.