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;
}
}
Is there any way possible to achieve running RhinoInside / Grasshopper to perform these Revit-Transformations?
Any pointers or help is much appreciated.
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:
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 {
`
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;
}
} ` .csproj:
I also tried posting my issue in https://github.com/galer7/run-grasshopper-demo/issues/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