Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Cannot run RhinoInside+Grasshopper Samples, any configuration #100

Open
edvinkuric opened this issue Jun 28, 2024 · 1 comment
Open

Cannot run RhinoInside+Grasshopper Samples, any configuration #100

edvinkuric opened this issue Jun 28, 2024 · 1 comment

Comments

@edvinkuric
Copy link

edvinkuric commented Jun 28, 2024

Hello, i am not sure if this is the correct Repo for posting my issue, but:

i have trouble running Headless Rhino/RhinoInside with Grasshopper-Plugin.

I get the following Exception, when using net481:
InvalidCastException: Unable to cast COM object of type 'System.__ComObject' to class type 'Grasshopper.Plugin.GH_RhinoScriptInterface'.

When using dotnetcore 7, i can't even load the correct DLLs or receive an "Error: HResult E_Fail has been returned from a call to a COM component", which i can't debug further.

Are there any restrictions on using specific versions?

My setup is:

  • current Visual Studio 2022 Community Edition (17.10)
  • both dotnet 481 and dotnet core 7 (dotnet core 8 is also installed, but didn't try that)
  • both Rhino 7 and 8 are installed
  • nuget-packages: .NET481: RhinoCommon + Grasshopper 7.36.23346.16351 (with custom RhinoInside-Resolver as well as the nuget-package with version 7.0.0), ; dotnetcore7: RhinoCommon + Grasshopper 8.7.24138.15431 (with custom RhinoInside-Resolver)
  • both Rhino-Versions are licensed and can be opened
  • Grasshopper is installed as Plugin
  • GH-Script is added as embedded Resource
  • Tried with Resolver-Flag "UseLatest" set to either true or false.

Ideally, i can run Rhino 8 Headless with dotnetcore 7 to be "future-proof", but i hadn't any luck for now.
I would also be happy, if i can run any variant for starters, but no Rhino 7 Licenses can be bought anymore.

My Grasshopper-Scripts uses revit-internal api to generate a rvt based on a DXF-File.
Can somebody help me with that or provide suggestions? That would be awesome - any hint helps

Here is the code, which i used/changed:

Program.cs: (adapted part)
`
namespace RhinoGrassHopperRunner
{
class Program
{

      static Program()
      {
          RhinoInside.Resolver.Initialize();
          Console.WriteLine("Initializing RhinoInside.Resolver");
      }

      static void Main(string[] args)
      {
          using (var core = new Rhino.Runtime.InProcess.RhinoCore())
          {
              RunHelper();
          }
      }

      // Currently need a separate RunHelper function so the .NET runtime won't attempt to load the
      // Grasshopper assembly until after RhinoCore has been created. This should be "fixable" in a
      // future version of the RhinoInside nuget package
      static void RunHelper()
      {
       // Extract definition to sample location as executable
       var assembly = typeof(Program).Assembly;
       string dir = System.IO.Path.GetDirectoryName(assembly.Location);
       var scriptName = "DXF2RVT.gh";
       string filePath = System.IO.Path.Combine(dir, scriptName);
      
       using (var resStream = assembly.GetManifestResourceStream("RhinoGrassHopperRunner." + scriptName))
       using (var outStream = new System.IO.FileStream(filePath, System.IO.FileMode.Create))
       {
           resStream.CopyTo(outStream);
       }
      var plugins = Rhino.PlugIns.PlugIn.GetInstalledPlugIns().OrderBy(x => x.Value);
      Console.WriteLine("plugins:", plugins.Select(x => x.Key + "  " + x.Value));
      // Start grasshopper in "headless" mode
      var plugin = plugins.FirstOrDefault(x => x.Value.Contains("Grasshopper")).Key;
      //if (string.IsNullOrEmpty(plugin))
      //{
      //    Console.WriteLine("Grasshopper not found");
      //    return;
      //}
      var pluginObject = Rhino.RhinoApp.GetPlugInObject(plugin);
      var type = pluginObject.GetType();
      var castedObject = (Grasshopper.Plugin.GH_RhinoScriptInterface)pluginObject;
      castedObject.RunHeadless();
      ....

`

Resolver.cs:

`
using System.Reflection;
using System.Runtime.InteropServices;

// Code from https://github.com/mcneel/compute.rhino3d/blob/8.x/src/compute.geometry/Resolver.cs
namespace RhinoInside
{
public class Resolver
{
///


/// Set up an assembly resolver to load RhinoCommon and other Rhino
/// assemblies from where Rhino is installed
///

public static void Initialize()
{
Console.WriteLine("Initializing RhinoInside.Resolver");
if (System.IntPtr.Size != 8)
throw new Exception("Only 64 bit applications can use RhinoInside");
AppDomain.CurrentDomain.AssemblyResolve += ResolveForRhinoAssemblies;
}

    static string _rhinoSystemDirectory;

    /// <summary>
    /// Directory used by assembly resolver to attempt load core Rhino assemblies. If not manually set,
    /// this will be determined by inspecting the registry
    /// 
    /// This is the C:/Program Files/Rhino 8/System directory on Windows
    /// This is the Rhinoceros.app/Contents/Frameworks directory on Mac
    /// </summary>
    public static string RhinoSystemDirectory
    {
        get
        {
            //return "C:\\Program Files\\Rhino 7\\System";
            // THIS USES THE RHINO 8 DIRECTORY
            if (string.IsNullOrWhiteSpace(_rhinoSystemDirectory))
                _rhinoSystemDirectory = FindRhinoSystemDirectory(); 
            return _rhinoSystemDirectory;
        }
        set
        {
            _rhinoSystemDirectory = value;
        }
    }

    /// <summary>
    /// Whether or not to use the newest installation of Rhino on the system. By default the resolver will only use an
    /// installation with a matching major version.
    /// </summary>
    public static bool UseLatest { get; set; } = true; // was true to use rhino8

    public static string AssemblyPathFromName(string systemDirectory, string name)
    {
        if (name == null || name.EndsWith(".resources", StringComparison.OrdinalIgnoreCase))
            return null;

        // load Microsoft.macOS in the default context as xamarin initialization requires it there
        if (name == "Microsoft.macOS")
            return null;

        //if (name.Contains("Rhino") || name.Contains("Grasshopper"))
        //{
            name = name.Split(',')[0];
        //}
        if (name.Contains("Grasshopper"))
        {
            systemDirectory = "C:\\Program Files\\Rhino 7\\Plug-ins\\Grasshopper";
        }
        else if(name.Contains("Rhino") && systemDirectory == null)
        {
            systemDirectory = "C:\\Program Files\\Rhino 7\\System";
        }
        string path = null;
        if (RuntimeInformation.IsOSPlatform(OSPlatform.OSX))
        {
            path = Path.Combine(systemDirectory, "RhCore.framework/Resources", name + ".dll");
        }
        else if (RuntimeInformation.IsOSPlatform(OSPlatform.Windows))
        {
            //path = Path.Combine(systemDirectory, "netcore", name + ".dll");
            if (!File.Exists(path))
            {
               path = Path.Combine(systemDirectory, name + ".dll");
            }
            if (!File.Exists(path))
            {
                var intPath = typeof(int).Assembly.Location;
                string directory = System.IO.Path.GetDirectoryName(intPath);
                path = Path.Combine(directory, name + ".dll");
                if (!File.Exists(path) || name.Contains(".Drawing") || name.Contains("WindowsBase"))
                {
                    int index = directory.IndexOf("NETCORE", StringComparison.OrdinalIgnoreCase);
                    directory = directory.Substring(0, index) + "WindowsDesktop" + directory.Substring(index + "NETCORE".Length);
                    path = Path.Combine(directory, name + ".dll");
                }
            }
        }
        return path;
    }

    static Assembly ResolveForRhinoAssemblies(object sender, ResolveEventArgs args)
    {
        string path = AssemblyPathFromName(RhinoSystemDirectory, args.Name);
        //// remove everything after first occurrence of ,
        //var cleanedName = path.Split(',');

        //path = cleanedName[0] + ".dll";

        if (File.Exists(path))
            return Assembly.LoadFrom(path);
        return null;
    }

    static string FindRhinoSystemDirectory()
    {
        var major = Assembly.GetExecutingAssembly().GetName().Version.Major;

        if (RuntimeInformation.IsOSPlatform(System.Runtime.InteropServices.OSPlatform.Windows))
        {
            string baseName = @"SOFTWARE\McNeel\Rhinoceros";
            using var baseKey = Microsoft.Win32.Registry.LocalMachine.OpenSubKey(baseName);
            string[] children = baseKey.GetSubKeyNames();
            Array.Sort(children);
            string versionName = "";
            for (int i = children.Length - 1; i >= 0; i--)
            {
                // 20 Jan 2020 S. Baer (https://github.com/mcneel/rhino.inside/issues/248)
                // A generic double.TryParse is failing when run under certain locales.
                if (double.TryParse(children[i], System.Globalization.NumberStyles.Any, System.Globalization.CultureInfo.InvariantCulture, out double d))
                {
                    if (d < 8.0)
                        continue;

                    versionName = children[i];

                    if (!UseLatest && (int)Math.Floor(d) != major)
                        continue;

                    using var installKey = baseKey.OpenSubKey($"{versionName}\\Install");
                    string corePath = installKey.GetValue("CoreDllPath") as string;
                    if (System.IO.File.Exists(corePath))
                    {
                        return System.IO.Path.GetDirectoryName(corePath);
                    }
                }
            }
        }

        return null;
    }
}

}
`
.csproj:
image

I also tried posting my issue in galer7/run-grasshopper-demo#1 , but the owner-repo also said that the examples are broken since the rhino 8 update, as seen in his reply.

Is there any way possible to achieve running RhinoInside / Grasshopper to perform these Revit-Transformations?
Any pointers or help is much appreciated.

Thank you very much!!
BR, Edvin

@dalefugier
Copy link
Member

@edvinkuric - can you move this to the Rhino.Inside category on Discourse?

https://discourse.mcneel.com/c/rhino-inside/110

Thanks,

-- Dale

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

2 participants