When running a .NET application compiled as AnyCPU, you cannot directly reference both x86 and x64 Eyeshot assemblies at the same time.
To overcome this limitation, use the helper class BitnessAgnostic, which dynamically loads the correct Eyeshot assembly at runtime and provides methods to read and write DWG/DXF files via reflection.
1. Prepare the environment
Since Eyeshot is now distributed through NuGet packages, you need to manually extract the runtime files for both architectures.
-
From your NuGet cache or installation directory, locate the following packages:
-
devDept.Eyeshot.x86.20xx.x.xxx -
devDept.Eyeshot.x64.20xx.x.xxx
-
-
Create two separate folders to hold the extracted binaries, for example:
C:\Program Files\devDept Software\Eyeshot 20xx\Bin\x86 C:\Program Files\devDept Software\Eyeshot 20xx\Bin\x64 -
From each package, copy the contents of the folders:
contentFiles\any\any\
lib\net8.0\ (or the target you need) runtimes\win-x86\native\ (or runtimes\win-x64\native\)into the corresponding
x86andx64folders.
2. Add the BitnessAgnostic helper class
Add the file BitnessAgnostic.cs (code below) to your project.
using devDept.Eyeshot;
using devDept.Eyeshot.Control;
using devDept.Eyeshot.Translators;
using System;
using System.Drawing;
using System.Reflection;
///
/// Helper class for dynamic loading of the Eyeshot x86 or x64 assembly.
///
public class BitnessAgnostic
{
public readonly string AssemblyPath;
public readonly Version Version;
public readonly System.Reflection.Assembly Assembly;
public BitnessAgnostic(string dllPath)
{
devDept.Eyeshot.Control.Workspace.GetAssembly(out _, out _, out _, out Version);
// Use the following code to check Operating System bitness
string target = System.Environment.Is64BitProcess ? "x64" : "x86";
string assembly = String.Format(@"devDept.Eyeshot.{0}.v{1}.dll", target, Version.Major);
AssemblyPath = System.IO.Path.Combine(dllPath, target, assembly);
if (System.IO.File.Exists(AssemblyPath))
Assembly = System.Reflection.Assembly.LoadFrom(AssemblyPath);
}
///
/// Gets an instance of the ReadAutodesk class.
///
public ReadFileAsync GetReadAutodesk(Design design, string fileName)
{
if (Assembly == null)
return null;
var foundType = GetObjectType("ReadAutodesk");
if (foundType != null)
{
// invokes the constructor
System.Reflection.ConstructorInfo constructor =
foundType.GetConstructor(new Type[] { typeof(string), typeof(string), typeof(bool), typeof(bool) });
if (constructor != null)
{
// parameters are: fileName, password, fixErrors, skipProxies
object reader = constructor.Invoke(new object[] { fileName, null, false, false });
return reader as ReadFileAsync;
}
}
return null;
}
///
/// Gets an instance of the WriteAutodesk class.
///
public WriteFileAsync GetWriteAutodesk(Design design, Drawing drawing, bool explodeViews, string fileName)
{
if (Assembly == null)
return null;
var writeAutodeskParamsType = GetObjectType("WriteAutodeskParams");
if (writeAutodeskParamsType != null)
{
// invokes the WriteAutodeskParams constructor
System.Reflection.ConstructorInfo constructor = writeAutodeskParamsType.GetConstructor(new Type[] {typeof(DesignDocument), typeof(DrawingDocument), typeof(bool), typeof(bool), typeof(double), typeof(bool) });
if (constructor != null)
{
// parameter is design
object writeAutodeskParams = constructor.Invoke(new object[] {design.Document, drawing?.Document, false, explodeViews, 1, false });
var writeAutodeskType = GetObjectType("WriteAutodesk");
if (writeAutodeskType != null)
{
// invokes the WriteAutodesk constructor
constructor = writeAutodeskType.GetConstructor(new Type[] {writeAutodeskParamsType, typeof(string)});
if (constructor != null)
{
// parameters are: writeAutodeskParams, fileName
object writer = constructor.Invoke(new object[] { writeAutodeskParams, fileName});
return writer as WriteFileAsync;
}
}
}
}
return null;
}
///
/// Gets an instance of the WriteAutodesk class.
///
public WriteFileAsync GetWriteAutodesk(Drawing drawing, string fileName)
{
if (Assembly == null)
return null;
var writeAutodeskParamsType = GetObjectType("WriteAutodeskParams");
if (writeAutodeskParamsType != null)
{
// invokes the WriteAutodeskParams constructor
System.Reflection.ConstructorInfo constructor = writeAutodeskParamsType.GetConstructor(new Type[] { typeof(DrawingDocument), typeof(bool), typeof(double), typeof(bool) });
if (constructor != null)
{
// parameter is design
object writeAutodeskParams = constructor.Invoke(new object[] { drawing.Document, false, 1, false });
SetProperty(writeAutodeskParams, "ForegroundColor", Color.Black);
var writeAutodeskType = GetObjectType("WriteAutodesk");
if (writeAutodeskType != null)
{
// invokes the WriteAutodesk constructor
constructor = writeAutodeskType.GetConstructor(new Type[] { writeAutodeskParamsType, typeof(string) });
if (constructor != null)
{
// parameters are: writeAutodeskParams, fileName
object writer = constructor.Invoke(new object[] { writeAutodeskParams, fileName });
return writer as WriteFileAsync;
}
}
}
}
return null;
}
///
/// Sets a public property via reflection
///
public bool SetProperty(object obj, string propertyName, object value)
{
PropertyInfo prop = obj.GetType().GetProperty(propertyName, BindingFlags.Public | BindingFlags.Instance);
if(prop != null && prop.CanWrite)
{
if (value is String && prop.PropertyType.IsEnum)
prop.SetValue(obj, Enum.Parse(prop.PropertyType, value.ToString()));
else
prop.SetValue(obj, value, null);
return true;
}
return false;
}
///
/// Gets the type matching the given class name from exported types.
///
private Type GetObjectType(string className)
{
Type foundType = null;
Type[] types = Assembly.GetExportedTypes();
if (types.Length 0)
{
foreach (Type type in types)
{
if (type.Name.Equals(className, StringComparison.OrdinalIgnoreCase))
{
foundType = type;
break;
}
}
}
return foundType;
}
}
This class detects the current process architecture and loads the appropriate Eyeshot DLL (x86 or x64) at runtime using reflection.
3. Example usage
// Initialize helper specifying the path containing the Eyeshot DLLs
var helper = new BitnessAgnostic(@"C:\Program Files\devDept Software\Eyeshot 20xx\Bin");
// Read DWG/DXF
var reader = helper.GetReadAutodesk(design, @"C:\Models\example.dwg");
reader.DoWork();
// Write DWG/DXF
var writer = helper.GetWriteAutodesk(design, drawing, false, @"C:\Output\exported.dwg");
writer.DoWork();
4. How it works
-
Detects if the current process is x86 or x64 via
Environment.Is64BitProcess. -
Loads the corresponding Eyeshot assembly dynamically with
Assembly.LoadFrom(). -
Instantiates the
ReadAutodeskorWriteAutodeskclasses using reflection. -
Provides helper methods like
SetProperty()andGetObjectType()to safely manipulate reflected types.
Comments
This dxf import works fine on all computers for me except one... and I can not understand why it does not work on one.
The crash occurs on "constructor.Invoke(new object[] {@"app8.dwg", null, false, false, false});"
Is there anyway to understand what can cause the crash inside of the constructor?
It looks like we need C++ redist v2019 for Eyeshot v2021. After installing this, it works as expected
Yes, from Eyeshot 2021 at least the C++ 2015 Redistributable version is required
Please sign in to leave a comment.