I do not have a reference to the grasshopper plugin in my project. Because when a new version of the plugin comes out, the class name is changed to XX_OBSOLETE, and the new plugin can have other parameters, so I use the guidId and reflection.
I solved the problem like this:
Find all assemblies loaded by grasshopper (AppDomain).
Look up all types in these assemblies with subclass GH_Component.
Create an instance for each type (GH_Component subclass) with Activator.CreateInstance (GH_COMPONENT TYPE); (I think grasshopper does this too)
In the created GH_Components find the guidid, if it matches send the type back to my own plugin.
Create another instance used by my plugin with Activator.CreateInstance ().
The steps 1 t / m3 are only done once. I just can’t run this code in the plugin’s constructor because not all plugins are loaded yet. I solved this by:
private void InitializeData ()
{
if (UsedComponentThread == null)
{
// THE PLUGINS THAT MUST BE USED
}
}
The InitializeData () method is called in the SolveInstance method.
I also made a system that reuses the instances created by Activator.CreateInstance ().
I also have a system that can create a grasshopper document per thread and the associated third party plugins that must be used. In this way each thread has its own grasshopper document and GH_Component instances. When a thread (Task) is ready, the document and components can be released again to be used in another thread. The main purpose of this code is to reduce the activation of the garbage collector. I can also use the plugins directly in Rhino.
I would like to perform steps 1 to 3 in the constructor.
That’s why I was wondering if grasshopper can load all the plugin first and then create an instance of the gh_component.
Wouldn’t this only solve the problem of one plugin referencing another?
When the assemblies (Runtime) are loaded with: Assembly.LoadFile (), other references that are needed are not loaded, but when Assembly.LoadFrom () is used all assemblies needed for the assembly are also loaded from the folder.
It may happen that a dllnotfound exception occurs, even though you have loaded this assembly with Assembly.LoadFrom (). I usually solve this with the event property: AppDomain.CurrentDomain.AssemblyResolve.
You should be able to just load the assembly you need on demand, and then when grasshopper loads that assembly as a plugin it’ll just directly use the already loaded data.
Good to know that Grasshopper checks if an assembly is already loaded.
I have just made an adjustment to my code. I now check in runtime if the assembly has been loaded by grasshopper if this is not the case I search with: Process.GetCurrentProcess (). MainModule.FileName for the path of rhino.exe, with this I can retrieve the plugin folder.
After this I load the assembly with: Assembly.LoadFile (fullPath);
I was hoping to multithread the loading of plugins in grasshopper 2.0 by the way, so this problem will become even more acute.
Indeed, with multithread it can happen that an assembly is loaded twice, since the Assembly. LoadFile is called by the constructor of a plugin that is dependent on another plugin.
I prefer not to use a direct reference in my project, because the class name, assembly version, sometimes changes. The guidId of a plugin remains the same and if this is not the case, grasshopper documents that use the guid id will no longer work properly.
Furthermore, the extension: gha to dll needs to be changed to be able to use the assembly in visual studio.
Just let me know if you agree.
I hope these explanations / reasons (and the previous post) are clear, I try to keep it as short as possible.
That’s just the way loading works in a .net appdomain as far as I know. I don’t do any special checking. But you’re right that Load, LoadFile and LoadFrom all behave slightly differently in this respect. I’ll have to double check my loading mechanism allows for this.
I do have a prototype being able to control load order by injecting code into Grasshopper using Harmony…
But I’d say generally it’s not an easy task to figure out references and load orders. And .NET Framework & Mono behaves very differently when loading a type for the 1st time.
Thanks for the reply. I think an assembly can be loaded multiple times with LoadFile (). I use LoadFile when I want to quickly test my assembly in grasshopper. I don’t have to keep restarting grasshopper.
I have created a clean sample project to reload an assembly without having to restart grahopper. But this is only for testing. I think the old assemby just stays in the memory.
Let me know if the example works properly. I had to adjust it a bit because I don’t have any dependencies that are not loaded by grasshopper.
[quote=“s_oosterhof, post:25, topic:115710”]
I use LoadFile when I want to quickly test my assembly in grasshopper. I don’t have to keep restarting grasshopper.
[/quote]
Could you elaborate about this please? How do you do it?
I have yet to find an elegant solution. The only thing I can think is Karamba defining these types in a separate project/dll that can be referenced by other parties. Seems like a bit of an exercise… ideally loading based on dependencies seems cleaner.
You can change the file extension from .gha to .dll so you can reference this in your code project and you have to include it along your .gha in the libraries folder. However I’m not sure how this will collide with the Karamba.gha, but I think it will work.
Try and reference .gha:
→ my addIn loads first and fails to load any components referencing types in karamba.gha
Try and reference .gha and copy to local (i.e. 2 copies, one in my AddIn one for karamba)
→ the karamba.gha is not loaded first and any components referencing types in karamba.gha are not loaded
Rename the .gha to .dll (and still copy)
→ Correctly loads the .dll as part of my AddIn and types are resolved. No mention of conflicts until I try to use the type from my AddIn with karamba components. One type is from the .dll and the other from the .gha and these are not compatible.
Is plugin loading “pretty much random” every time Grasshopper runs? No preference for defaults that ship with GH? I see tabs in R7/GH 1.0.0007 appearing from sources in the following locations: