Grasshopper

algorithmic modeling for Rhino

Hello,

I am wondering what are the best practices when we have external DLLs that we have to reference in our components and also need to be distributed with the gha?

I have a set of api libraries provided by the source as an installer.  The user could change the installer, but by default, this location should be the same (Program Files(x86)\...).  On my machine, I can run the gha from its development release folder with the referenced libraries NOT copied locally.

When trying this on test machines, running the APIs installer, and copying the gha to the GH User libraries folder, GH cannot find the DLLs.  Copying them into the GH User Libraries folder fixes this.

I would like that the user do as little work as possible in this case and avoid having to copy the DLLs into the GH User Libs folder.

Can anyone suggest the best way to deal with this issue?  The DLLs are not available as source code, so I cannot include the code in the gha.

Thanks!

Luis

Views: 2600

Replies to This Discussion

If you want to install dlls along with a GHA file, we recommend using an RHI installer. I think at present RHI doesn't yet support GHA only installs but that should be fixed soon.

Basically somebody has to be able to find these dlls, it's either:

  • The system, by putting the dlls next to the executing assembly or in the Global Assembly Cache
  • Rhino+Grasshopper, by putting the dlls next to the assembly file or any other location where we expect to find relevant assemblies (basically always next to plugins and GHA files)
  • The assembly itself, by implementing an AssemblyResolver event handler or specifically loading the assemblies from disk prior to any calls into those assemblies

Handling the AssemblyResolve event is a good solution if you cannot install the dlls next to your gha file.

--

David Rutten

david@mcneel.com

Tirol, Austria

Ok, now saying that I am able to load remote assemblies, is there a way to do so as GH is starting up and loading up my components?  Another option is to have them loaded once one of a group of components that uses the assemblies is placed on the canvas.  I guess what I'd like to avoid is that they get loaded every time one of these components is placed on the canvas.

I saw this older post: http://www.grasshopper3d.com/forum/topics/only-get-plugin-working-i...

It mentions the GH_AssemblyPriority Interface.  If I make a file with such a class, will it automatically load the assemblies referenced there with the

Rhino.Runtime.AssemblyResolver.AddSearchFile("pathtomy.dll");

?

I've tried this, but still getting Solution Exception Errors: Could not load file or assembly... on the class I am trying to use from the third party dll.  All of this works fine if the dlls are copied locally.  This is what I am trying to avoid.

My code for this file is as follows:

class AddReferencePriority: GH_AssemblyPriority
    {
        public override GH_LoadingInstruction PriorityLoad()
        {

           Rhino.Runtime.AssemblyResolver.AddSearchFile("pathto1.dll");
           Rhino.Runtime.AssemblyResolver.AddSearchFile("pathto2.dll");
           Rhino.Runtime.AssemblyResolver.AddSearchFile("pathto3.dll");
           return GH_LoadingInstruction.Proceed;
        }
    }

does this mean that any other class calling these assemblies will have access to them, or are they out of scope to the rest of my components in the gha?

Why not just load the assemblies at this stage? All code that references these assemblies (or assemblies that .NET deems compatible) will use the already loaded ones as far as I know. So if you load these three dlls from within PriorityLoad, then it should work from then on.

The only reason not to load them right away is if they:

A) Take a long time to load.

     -or-

B) Take up a lot of memory.

     -and-

C) The user might not need them at all.

Using the RhinoCommon resolver will be much slower than loading the dlls yourself.

--

David Rutten

david@mcneel.com

After messing about with Reflection and trying such things:

System.Reflection.Assembly ass = System.Reflection.Assembly.LoadFrom(@"pathtomy.dll");

Type myType = ass.GetType("NameSpace.Class.TypeName");
object[] args = new object[] { (object) "constructor args"};
object myTypeInstance = Activator.CreateInstance(myType, args);

It seems a huge pain in the ass to always be invoking members, digging to get events, etc.  That is, unless I can get access to the types defined in the dll in some other way.  (By the way, some version of the above code does 'work' as I am not seeing any issues thrown, just seems inconvinient to not be able to use the needed types directly).

Since the type is not known yet by the code, I cannot cast myTypeInstance as the type I need.  Is there a better way to go about this?  I am about to throw in the towel and just include the dlls next to the gha.  This is an interesting article, but it makes the whole reflection thing very unattractive for this particular use case.

You reference the dll in your project, make sure it's CopyLocal=False, then you can use regular method and type invocation. The first time any code that uses this assembly runs .NET will need to find the dll. If you manage to load it ahead of time it should just find it already loaded in memory. 

--

David Rutten

david@mcneel.com

Sooo...

I have this as my Priority Loading:

class AddReferencePriority: GH_AssemblyPriority
    {
        public override GH_LoadingInstruction PriorityLoad()
        {

                Assembly ass1 = Assembly.LoadFile("pathto1.dll");         
                Assembly ass2 = Assembly.LoadFile("pathto2.dll");

                Assembly ass3 = Assembly.LoadFile("pathto3.dll");

                return GH_LoadingInstruction.Proceed;
        }
    }

I am still getting loading errors.  Does this class need to be anywhere in particular, or does GH look in the assembly (gha) namespace, finds it, and runs it first?

p.s. I have tested the above code separately to make sure that the files can be found, etc.

It finds it and runs it. Did you put a breakpoint on the code inside PriorityLoad to make sure the code is run? I keep forgetting what the default accessor is for types in C#, I'd put a public in front of class just to be sure.

--

David Rutten

david@mcneel.com

ding ding ding! We have a winner.  Adding 'public' to the class made it work.  Thanks a bunch!  Now to predict where users might have those assemblies!

For reference, the final class was as such:

public class AddReferencePriority: GH_AssemblyPriority
    {
        public override GH_LoadingInstruction PriorityLoad()
        {
                Assembly ass1 = Assembly.LoadFile("mypath1.dll");
                Assembly ass2 = Assembly.LoadFile("mypath2.dll");
                Assembly ass3 = Assembly.LoadFile("mypath3.dll");
                return GH_LoadingInstruction.Proceed;
        }
    }

Now to predict where users might have those assemblies!

If you can't find them even after extensive searching, you can always ask the user, then cache the resulting paths somewhere.

--

David Rutten

david@mcneel.com

RSS

About

Translate

Search

Videos

  • Add Videos
  • View All

© 2024   Created by Scott Davidson.   Powered by

Badges  |  Report an Issue  |  Terms of Service