The following source code sample demonstrate how to load DWG/DXF files from a .NET application compiled against AnyCPU. It includes the operating system bitness detection, dynamic loading of the Eyeshot x86 or x64 DLL from a separate folder and the instantiation of the ReadAutodesk class using reflection.
Comments
Our project is referencing other controls that have x86 and x64 DLLs and we use several methods from these controls. We searched a more type-safe and ‘friendly’ approach and found a very clever solution developed by Yurik on stack exchange. http://stackoverflow.com/a/9951658
In a nutshell, before anything we subscribe to the AppDomain.CurrentDomain.AssemblyResolve event (which is raised when the application is looking for a DLL) and intercept the call and replace the requested DLL with the platform specific version that we simply put in x86 and x64 subfolders of the application. For in-depth details, please see the original solution on stack exchange.
The big difference from Alberto’s approach is that you reference the x86 version of the DLL in your Visual Studio project. So you can use the ReadAutodesk class, like any other without invoking methods and constructors using reflection.
I’ve updated Alberto’s sample with this technique (see attached project).
Some additional information:
http://stackoverflow.com/a/12672514
<PropertyGroup>
<ResolveAssemblyWarnOrErrorOnTargetArchitectureMismatch>None</ResolveAssemblyWarnOrErrorOnTargetArchitectureMismatch>
</PropertyGroup>
Good luck with your projects.
Alex
VB.NET code
Protected Overrides Sub OnLoad(e As EventArgs)
Dim appPath As String = Path.GetDirectoryName(Application.ExecutablePath)
Dim pathDll As String
' checks Operating System bitness
If Environment.Is64BitProcess Then
pathDll = appPath & Convert.ToString("\x64\devDept.Eyeshot.Control.x64.dll")
Else
pathDll = appPath & Convert.ToString("\x86\devDept.Eyeshot.Control.x86.dll")
End If
If Not File.Exists(pathDll) Then
Return
End If
Dim foundType As Type = Nothing
Dim assembly__1 As Assembly = Assembly.LoadFrom(pathDll)
Dim types As Type() = assembly__1.GetExportedTypes()
If types.Length > 0 Then
For Each type As Type In types
If type.Name.Equals("ReadAutodesk", StringComparison.OrdinalIgnoreCase) Then
foundType = type
Exit For
End If
Next
End If
If foundType IsNot Nothing Then
' invokes the constructor
Dim constructor As ConstructorInfo = foundType.GetConstructor(New Type() {GetType(String), GetType(String), GetType(Boolean), GetType(Boolean)})
If constructor IsNot Nothing Then
' parameters are: fileName, password, fixErrors, skipHatches
Dim reader As Object = constructor.Invoke(New Object() {"app8.dwg", Nothing, False, False})
' invokes the DoWork() method
Dim mi As MethodInfo = foundType.GetMethod("DoWork", New Type() {})
mi.Invoke(reader, New Object() {})
' invokes the AddToScene() method
mi = foundType.GetMethod("AddToScene", New Type() {GetType(ViewportLayout)})
mi.Invoke(reader, New Object() {viewportLayout1})
Else
MessageBox.Show("Unable to get the ReadAutodesk constructor.")
End If
Else
MessageBox.Show("Unable to get the ReadAutodesk class.")
End If
' fits the drawing in the viewport
viewportLayout1.ZoomFit()
MyBase.OnLoad(e)
End Sub
Working on a larger WPF solutions (10+ individual projects), I need DWG read in two of these project, and HiddenLinesViewOnFileAutodesk two other placed.
The solution described in this thread, using reflection, works fine; but to avoid writing the same code in four projects, I wrote a little wrapper class, to take care of the work.
Please find attached project, where devDept's BitnessAgnosticReadDWG_WPF is modified, using my wrapper class.
In order to keep size down, the content of bin/debug/X86 and bin/debug/x64 folders are not included, please copy from your own installation, remember to replace dll's i root, if you use a different version/build)
This sample is build with EyeShot NURBS edition build 250.
Feel free to use this code as is, or modify/extend in anyway you like.
Regards
Flemming
Thanks Alex. Your solution worked for our product that was redesigned to build using AnyCPU.
As the x86 assembly is referenced by the built assembly, but missing (Copy Local=false), the MultiPlatformDllLoader class is looking for 'devDept.Eyeshot.Control.x86.dll'. When installed on a 64-bit OS this this caused the software to fail as it could not find 'devDept.Eyeshot.Control.x86.dll' not (not installed) when the actual installed library was 'devDept.Eyeshot.Control.x64.dll'.
As a quick workaround for this we added a check for this specific file in MultiPlatformDllLoader after the code getting the assembly name:
switch (assemblyName)
{
case "devDept.Eyeshot.Control.x86.dll":
{
if(Environment.Is64BitProcess)
assemblyName = "devDept.Eyeshot.Control.x64.dll";
}
break;
}
This system also highlighted another issue that we had not previously identified. When we changed to AnyCPU we found that ours was still running as 32-bit as the build setting of the project has a 'Prefer 32-bit' option that was checked.
Hope this helps others.
Hi Richard,
I’m glad the solution worked for your product. Since I posted this, I had similar problems as you.
The 'Prefer 32-bit' option tricked me too. Since then, while debugging, in order to ensure I’m running in 64 bits, I added something like this in my ViewportLayout descendant:
Since we use many libraries that require platform specific version, we use a string,string dictionary in the assembly loader. This way we can easily add ‘name pairs’ of DLLs that don’t have the same name in X86 vs X64. Below is our latest code for the assembly loader.
HTH
Alex
Hi guys,
Some comments mention attached projects but I cannot see any attachments. Any clue?
Best Regards,
Panagiotis
Hi Panagiotis,
I don't know why the attachments are removed from the posts. If you want, I could recreate the example I posted back then.
Alex
Hi Alex,
Thanks for replying. I would be grateful if you could so :)
Best Regards,
Panagiotis
Hi Panagiotis,
It seems I cannot attach anything to my post. I've uploaded it to file.io here:
https://file.io/GxlUiU
Not sure how long it'll be there so hurry ;)
I've taken the project attached at the top of this thread and converted it VS2017-Eyeshot V10 and integrated pretty much everything I discussed in this thread. High level instructions:
-Add MultiPlatformAssemblyLoader.cs to project
-Put your dll names in the MultiPlatformAssemblyLoader.Assemblies dictionary
-Enable MultiPlatformAssemblyLoader in program.cs
-Edit project properties. On Build tab make sure platform target is AnyCPU and Prefer 32-bit is unchecked
-Add a reference to your x86 dll devDept.Eyeshot.Control.x86.v10.dll
-Change the devDept.Eyeshot.Control.x86.v10.dll reference ‘Copy Local’ property to False.
-Edit the csproj file to add the propertygroup to remove the x86 in AnyCPU warning in Visual Studio
-Add post-build event to copy X86 and X64 Eyeshot folders to the output folder <-- you might need to change the path if you installed eyeshot elsewhere
Hi Alex,
Thank you very much! Indeed the project is not there anymore but I think I managed to implement this. Up to now it seems to be working. I really appreciate your help and time!
Best Regards,
Panagiotis
Please sign in to leave a comment.