VSTO addin dependency resolution - plugins

I have a VSTO addin, which works fine. I am trying to give it a plugin-loading mechanism so that others can add plugins to my plugin. I sounds horrific, I know, but it seems to best option for now.
I publish my addin to a folder called 'Published'. This creates the application manifest (Symbols.application) and also a folder called Symbols_x.y.xx.yy with the actual addin assemblies in it. Visual Studio increments this version number each time I publish, so the assemblies are never in the same place twice.
The plugins are in a folder Published\Plugins. I load the plugin assemblies using Assembly.LoadFile(string) and this works OK. The plugins are all in folder which stays in the same place no matter how many times I publish it and I can scan that folder for DLLs and load them.
What doesn't work is when those plugin DLLs have dependencies. In particular, one depends on a COM object. Visual Studio builds an automatic Interop DLL which it puts in the Published\Plugins folder, alongside the corresponding plugin DLL. An exception is thrown as soon as any attempt is made to access the COM object, saying that the interop assembly could not be found.
Putting the interop DLL into the folder Published\Symbols_x.y.xx.yy folder works, but that requires manually putting it there each time. I've tried adding the plugins to the AppDomain's PrivateBinPath, but the documentation says that anything outside the ApplicationBase will be ignored and it seems this is indeed the case - it doesn't work. ApplicationBase is set to Published\Symbols_x.y.xx.yy.
It seems to me I have four options:
Figure out how to change the ApplicationBase, moving it up one level, and then add the Published\Plugins folder to the AppDomain's PrivateBinPath.
Make some change to the application manifest to indicate that assemblies can be loaded automatically from Published\Plugins.
Find some other way of explicitly loading an assembly into the AppDomain, not just into memory using Assembly.LoadFile.
Anything else anyone wants to suggest!
But I can't find any way to get any of these options to work. Help!

The solution was provided by the MSDN forums:
I've added an event handler to AppDomain.CurrentDomain.AssemblyResolve. This gives you a chance to load the assembly in whatever way you like, including by loading it from my plugins directory.

Related

CRM could not load file or assembly to my project

I added a reference itextsharp.dll to my plugins project, when running my plugins using plugin-registration tool I get this exception:
Could not load file or assembly or one of its dependencies. The system
cannot find the file specified
I tried removing the ref and adding it again, cleaning and then adding it to my project from different places.
Is there restrictions in plugin registration tool about adding non crm dlls? why ? how to solve it?
This is not going to work - you cannot reference external assemblies from CRM plugins that are registered in database. If you want to do this, you will have to merge your external dll with your plugin assembly. You have to remember that adding assembly as reference is not automatically making your referenced assembly available for your base assembly, therefore if you register your plugin assembly in CRM, system is not going to "magically" find somewhere your external assembly (in your case - "itextsharp.dll"). If this is not Online system, you can add your assembly to GAC, or register all your assemblies on Disk instead of database (not recommended approach). If you want to register them in database, you will have to merge everything in one assembly using ILMerge for example.
You can't reference something in a plugin unless it's in the bin of the CRM.
To make it work you need to ILmerge your reference with the plugin. Install this package in your project: MSBuild.ILMerge.Task. Then build. It will work instantly. The package will merge everything in the bin after the build. So make sure every other references are marked "Copy Local = false". Otherwise, you'll have a crazy big assembly.
Finally, Microsoft released a solution for this. You can build a nupgk file and register dependent assemblies.
Here are the white paper and my post about this;
Microsoft : Microsoft White Paper
My summary: Here is the link

How to deploy ONLY .EXE and custom .BPL files?

I would like to develop GUI application with plugins. The plugins contains VCL Forms which are inherited from Base Forms in the Plugin-Core library. The main application can select which plugin to load dynamically, and then which Form subclasses to display.
In the users side, I would like to deploy main .EXE, the Plugin-Core library, and many plugin libraries for different models. I could release new or modify existed plugin libraries to users to display new Forms for new devices without modifying the main .EXE and the Plugin-Core library.
The first version I developed uses DLL approach, namely both the Plugin-Core library and the plugins are in DLL form. Everything is just fine on the users side. However, in the developers side, the plugin DLL project can not be linked without Base Forms defined in the Plugin-Core DLL project. It means that the Base Forms are actually statically linked in each plugin DLL project, and if someday I modify the Base Forms and rebuild the Plugin-Core DLL project, I have to rebuild all plugin DLL projects and re-release plugin .DLL s to users, too.
After searching and asking in StackOverflow, I realized the limitation that VCL Forms can NOT be inherited across DLL boundary is due to RTTI conflict(?). The suggested solution is to modify the libraries from DLL to BPL form, which is the second version I developed. Everything is also fine except the following two:
The dynamic loaded Form from plugin BPL is separated from the main .EXE in Windows taskbar. It is not what I desired. The solution is that I enabled "Build with runtime packages" in the .EXE project.
After I enabled "Build with runtime packages" in the .EXE project, I have to release other .BPLs to the users, such as vcl.bpl and rtl.bpl. This is not perfectly what I desired.
I would like to know that the above two issues can be resolved at the same time? In my thought, I could resolve both two issues if I:
Disable "Build with runtime packages" in .EXE project.
Enable "Build with runtime packages" in all .BPL projects.
In this way, the .EXE can run without vcl.bpl and rtl.bpl bundled, and the plugin .BPL s can be loaded successfully because the dependent units are already part of the main .EXE? Am I correct? However, the "Build with runtime packages" checkbox is disabled in all .BPL project options. As a result I don't have a chance to check whether the solution works or not. I am sorry for the lengthy description and I can not attach picture due to company's Internet security policy.
The dynamic loaded Form from plugin BPL is separated from the main .EXE in Windows taskbar. It is not what I desired. The solution is that I enabled "Build with runtime packages" in the .EXE project.
After loading a BPL, pass the EXE's Application.Handle to the BPL and assign it to the BPL's own Application.Handle before it creates any Form instances.
Alternatively, on Windows 7+, you can have the EXE call SetCurrentProcessExplicitAppUserModelID() to establish a App ID for its taskbar button. Then each Form in the BPLs can use SHGetPropertyStoreForWindow() and IPropertyStore.SetValue(PKEY_AppUserModel_ID) to set the same App ID for their windows. Multiple windows with the same App ID are grouped together under a single taskbar button.
See MSDN for more details: Application User Model IDs (AppUserModelIDs)
I would like to know that the above two issues can be resolved at the same time? In my thought, I could resolve both two issues if I:
Disable "Build with runtime packages" in .EXE project.
Enable "Build with runtime packages" in all .BPL projects.
In this way, the .EXE can run without vcl.bpl and rtl.bpl bundled, and the plugin .BPL s can be loaded successfully because the dependent units are already part of the main .EXE? Am I correct?
No. BPLs cannot use the EXE's built-in units like that.
If you disable "Build with Runtime Packages", the RTL/VCL units will be statically linked into the executable file. The problem with doing that is multiple copies of a given unit cannot be loaded in memory at the same time, so you wouldn't be able to load multiple BPLs together (or even at all) if the same RTL/VCL units are statically linked into multiple BPLs, or even the EXE itself.
If you enable "Build with Runtime Packages", the executable file will be dependent on the RTL/VCL BPLs, which must then be deployed.
So, if your EXE and BPLs share common units, those units must be loaded via shared BPL(s) so only one copy of the units exist in memory. There is no avoiding that when writing custom BPLs. Which means at a minimum you usually have to deploy RTL.BPL if you are using basic RTL functionalities, and VCL.BPL for UIs.

Should a binding redirect work for external dlls?

Scenario:
I just upgraded all the projects in my solution to a new version of PostSharp (shouldn't matter the library, hopefully.) I have around 20 projects in my solution and around half of them originally referenced version 3.0.42 and I just updated them all to the latest version. My solution contains a web app that references projects within this solution, as well as some external dll references. It just so happens that some of those dll references also had dependencies on PostSharp version 3.0.42 and I'm now getting the typical "The located assembly's manifest definition does not match the assembly reference." error from those external dlls when trying to run my app. The web.config has the appropriate bindingdirect in place. Is there any way to have the bindingrediect impact my external dlls as well? Rebuilding them with the latest PostSharp dll is not currently an option.

Duplication of resource folders within an Eclipse Project

I am writing an Eclipse Plug-in which requires me to add two new configurations to the ManagedProject upon mouse-click on a menu option. I basically runs on Android projects that has Native Support Added to it. I am trying to achieve this using ManagedBuildManager and Configuration classes from the CDT core plug-in interfaces.(org.eclipse.cdt.managedbuilder.core.* package).
To complete the task, I create two new Configurations for the project and run the exportArtifactInfo() method to complete the action. In the end, the configuration gets added but the project folder contains duplicate folders of all the original folders in the Project folder.
I looked up if there is a bug in CDT 4.0 and found that it is indeed a resolved bug.
https://bugs.eclipse.org/bugs/show_bug.cgi?id=194395
But I cannot figure out what the actual fix is for this bug. If anyone has encountered and fixed it or knows how to fix this, please point me in the right direction.

Referencing a GWT project from another GWT one - Problems

I am already using an open source GWT project (iServe) and I would like to integrate into it another open source GWT project (PetalsBPM), by which I mean being able to call it and reference its methods.
I have imported iServe in Eclipse (it has multiple modules) as separate Maven projects referencing its other and can run it successfully through Runas -> Web application in development mode.
If I do that and run the other project through the console as mvn gwt:run, I call initiate PetalsMBP through iServe. However, that means that the two programs have to run as is, without communication with each other.
I have also imported the second project into eclipse as a java project successfully (converting into a Maven one causes problems - various lifecycle configurations ones), but whenever I try to add to to iServe through Properties -> Java Build Path -> Projects, although it does not cause any errors immediately, I cannot launch iServe anymore. It produces the following error:
"Exception occurred executing command line.
Cannot run program "C:\Program Files\Java\jre7\bin\javaw.exe" (in directory "C:...iserve-sal-gwt-1.0.0-SNAPSHOT"): CreateProcess error=206, The filename or extension is too long"
Are my problems related to the fact that PetalsBPM is not a Maven project in Eclipse (I doubt it)?
Am I doing something wrong, i.e., this is not the way to reference a project from another one? should I add a reference to the first project's (iServe) gwt.xml file?
Is there a way to do what I want without having to wrap the second project as a jar and calling it from iServe? I would prefer not to, since producing a jar every time I make a slight change is not exactly efficient!
P.S: The second project is a regular GWT project with an entrypoint, not just a module. Should I remove this?
UPDATE: Trying to figure out the source of this error, I attempted to simplify the problem, so I performed the following moves:
I created two new simple GWT projects and tried to reference one
from the other. Worked fine
I referenced the project I actually want
to use (PetalsBPM) from the simple one I just created. Also works
fine.
I referenced the new simple project from the original one I
want to use (iServe). Also works fine.
Tried doing what I actually
want to do, copying the settings from 2&3. Produces the same error
"CreateProcess error=206, The filename or extension is too long" if
I reference PetalsBPM (does not when I remove it from the referenced
projects)
So, I tried switching workspaces. I created a new workspace in C:\, and moved the actual projects there. Still it did not work. :(
Any more ideas?
I met the same type of error "Create Process, error=206, path too long etc." a hundred times.
Then, I found a solution/explanation in google-groups, it solved my problem.
I post the content and link as it might help others.
This website (StackOverflow) really helped me a thousand times.
Thanks to you all !
solution/explanation :
(Response from Stephen Johnson)
(...) if you're using eclipse plugin go to Project | Properties, choose
Google \ App Engine \ ORM and only include directories that you have
classes that you want enhanced. By default it does the entire project
so that includes a lot of needless files. (...)
Link :
original post # google-groups
Read the exception message again. Somewhere along the way Maven is generating a path that is too long for (some) Windows API to handle, try moving your workspace to a directory straight below C:\.
I just tried "skolima" reply and it worked for me. In Eclipse I clicked File->Switch Workspace.
Three things to note:
After I created the workspace in "C:\workspace" I had to update my Project->Properties > Java Build Path > Libraries > Add External JARs...
I'm using Windows 7.
I'm using "Eclipse Java EE IDE for Web Developers"
I hope this others.