Quantcast
Channel: Questions in topic: "dll"
Viewing all articles
Browse latest Browse all 706

Import (mixed assembly) managed C++/CLI DLL plugin

$
0
0
**This post covers my experiences with managed C++/CLI DLLs and ends with the question if it is possible to do it. Up to now I haven't been able to make it work.** ---------- So I do have some heavy and powerful C++ DLLs I need to use in my project. According to the [Unity documentation][1] there are two ways - Managed plugins (e.g. C# or C++/CLI) - Native plugins (e.g. C++) Since it would be easier to use in Unity I tried the managed C++/CLI path. C++/CLI is a language developed by Microsoft to write managed C++ code which can use managed (.NET) and native (C++) functions as well as data structures. There is no need to do P/Invoke if we use the **/clr** compiler options and there's also no marshaling. Sounded about right. # Managed Plugin with C++/CLI # ## Prequisites ## So we need to write a managed C++/CLI DLL in Visual Studio since this is the only environment [offering a C++/CLI compiler][2]. Since Unity uses an older version of [Mono][3], we're limited to version 3.5 of the .NET framework and version 2 of the [CLR][4] ([Source][5]). This means we need to install Visual Studio 2008 Express since this is the last version shipping .NET 3.5 ([Source][6]). Also I needed a 64 bit compiler since it is [not shipped with VS 2008 Express][7]. But it can be downloaded [here][8] as a part of the Windows SDK. ## Project Hierarchy and Setup ## Following [this][9] advises I created a VS solution consisting of two parts: 1. An interface written in C# 2. An implementation of that interface in C++/CLI that should eventually use my C++ DLLs Furthermore we have a Unity C# script that uses and accesses the imported DLLs in Unity. One of the main reasons to go this way is to overcome the issue that Unity doesn't release DLLs once they've been used the first time ([Source][10]). So loading the during runtime sounded about right. Plus I can directly deploy new versions of my C++/CLI DLL into the Unity folder and don't have to import it manually. (Turned out, that Unity also doesn't release these DLLs. So one can either restart Unity or try to use this [hack][11])). ### C\# Interface ### This is the interface stub: namespace IInterface { public interface IInterface { string Function1(string value); } } It's compiled to a DLL using Visual Studio and selecting .Net Framework 3.5 as target framework. The DLL is imported into Unity as a normal asset/plugin to allow Unity to know about the interface. ### C++/CLI Class implementing the interface ### **Header file:** using namespace System; using namespace IInterface; namespace InformationExtractor { public ref class InformationExtractor : public IInterface { public: virtual String^ __clrcall Function1(String^ value); }; } **C++-file:** #include "stdafx.h" #include "InformationExtractor.h" String^ __clrcall InformationExtractor::InformationExtractor::Function1(String^ value) { return value + value; } Obviously depending on **IInterface** this is built to a 64bit DLL called *Information_Extractor.dll* setting the following features: - Platform Toolset: Visual Studio 2008 (v90) - Common Language Runtime Support: Common Language Runtime Support (/clr) In my case I deployed it directly to the project folder of my Unity project (**not** the asset folder) to avoid the manual import process. Up to here the code is verified to work within the .NET framework. So if I add another C# project to my Visual Studio solution, I can instantiate an object and call the function. ### Unity C\# Script ### This is the Unity script using the DLL using UnityEngine; using System.Collections; using System.Reflection; using System; public class TestScript : MonoBehaviour { void Awake () { Assembly dll = Assembly.LoadFile("Information_Extractor.dll"); System.Type Extractor = dll.GetType("InformationExtractor.InformationExtracter"); IInterface.IInterface extractor = (IInterface.IInterface)Activator.CreateInstance(Extractor); Debug.Log(extractor.Function1("Hello World!")); } } The DLL Import code is derived from the same solution that also pointed out the [interface idea][12]. So what we do is to load the *Information_Extractor.dll* which is in the Unity project folder, extract the class, instantiate an object and call the function. Here's where the trouble starts. So we make a little extra tour to Mono. ## Unity and Mono ## Unity uses the Mono implementation of the .NET framework, so we're limited to what Mono can do for us. As of version 5.3.4f1 of Unity it is shipped with Mono 2.0.50727.1433. (Find out using [this command][13]) So that (derived) runtime version of Mono has to be able to deal with our DLL. But according to the [Mono C++][14] homepage, Mono can't deal with CLI if the code is a mix of CIL and native code, which is usually produced by the VS compiler. ## Compiling the C++/CLI DLL ## Microsoft's C++/CLI language allows us to use different compiler flags: - /clr - /clr:pure - /clr:safe A basic explanation of their capabilities can be found in this [blog post][15]. A feature comparison is [here][16]. You can set this flag in the projects properties under *Configuration Properties* -> *General* -> *Common Language Runtime Support*. ### Using /clr ### Import the DLL using the code above throws [this][17] **BadImageFormatException** ([Reference on MSDN][18]). According to the MSDN article about [Assembly.LoadFile][19] this can happen if the format is not valid or another version of the CRT is used. My personal guess is, that Mono throws this exception since the DLL is a mixed assembly and not solely featuring CIL instructions since the same compiler settings work with "/clr:safe". ### Using /clr:pure ### Compiling this C++/CLI DLL using the /clr:pure compiler option throws another exception \*huray\*. [This time][20] it's a **NotImplementedException** when instantiating the class. According to the [MSDN Article][21] about Activator.CreateInstance, this function can't throw a NotImplementedException. So this should be a Mono thing. According to the [Mono C++ page][22] mentioned earlier this is probably thrown due to Mono's lack to have implemented the CRT DLL. To overcome this, Mono suggests to add this signature to the code: #pragma warning(disable:4483) void __clrcall __identifier(".cctor")() { } and to follow this [MSDN article][23] to create compiled code without a reference to the CRT DLL. That actually worked for me, but when I started to add my native C++ code and tried to create an object using the keyword "new" in my C++/CLI DLL (using [this][24] technique), Unity/Mono complained about not finding a the MSVCR90D.dll by throwing an exception \*huray²\*. DllNotFoundException: MSVCR90D.dll .new (UInt64 size) InformationExtractor.InformationExtractor.initialize () TestScript.Awake () (at Assets/Scripts/TestScript.cs:20) One can just add this DLL to the Unity project folder, but that makes Unity crash and is probably also not the way we want to go. ### Using /clr:safe ### This actually works in terms of - I can import the DLL and call functions. This works even without the Mono-avoid-CRT workaround since CRT is not allowed in /clr:safe ([Source][2]). But as far as I've understood the feature set of this flag, it also doesn't really help me to access and use my native C++ DLLs since I'm limited to P/Invokes which I can also use with a native plugin. In contrast to "/clr:pure" (as far as I've understood it) it is also not possible to use native types. ## Conclusion and Question ## Not mentioning a lot of pitfalls, that's how far I got. My current conclusion is, that there's no easy and good way to use a C++/CLI DLL in Unity. But I'm very open for suggestions or tips about how to use them. Meanwhile, I'll start to develop a native plugins since this seems the way to go. [1]: https://docs.unity3d.com/Manual/Plugins.html [2]: http://www.mono-project.com/docs/about-mono/languages/cplusplus/ [3]: http://www.mono-project.com/ [4]: https://msdn.microsoft.com/en-us/library/8bs2ecf4(v=vs.90).aspx [5]: http://forum.unity3d.com/threads/unity-c-3-5-or-2-0-net-unityscript-mono-clr-cil-and-assemblies-explained.343450/ [6]: http://stackoverflow.com/questions/212896/how-do-the-net-framework-clr-and-visual-studio-version-numbers-relate-to-each [7]: http://stackoverflow.com/questions/9536357/how-can-i-compile-64-bit-with-visual-c-2008 [8]: https://www.microsoft.com/en-us/download/confirmation.aspx?id=3138 [9]: http://answers.unity3d.com/questions/191514/how-i-make-some-code-outside-unity-.html [10]: http://runningdimensions.com/blog/?p=5 [11]: http://runningdimensions.com/blog/?p=5 [12]: http://answers.unity3d.com/questions/191514/how-i-make-some-code-outside-unity-.html [13]: http://answers.unity3d.com/questions/259448/how-to-determine-mono-version-of-unity-.html [14]: http://www.mono-project.com/docs/about-mono/languages/cplusplus/ [15]: https://blogs.msdn.microsoft.com/abhinaba/2012/11/14/ccli-and-mixed-mode-programming/ [16]: https://msdn.microsoft.com/en-us/library/ms173252(v=vs.90).aspx [17]: http://pastebin.com/vWefxnGQ [18]: https://msdn.microsoft.com/en-us/library/k7137bfe(v=vs.90).aspx [19]: https://msdn.microsoft.com/en-us/library/b61s44e8(v=vs.90).aspx [20]: http://pastebin.com/UftNEbnL [21]: https://msdn.microsoft.com/en-us/library/wccyzw83(v=vs.90).aspx [22]: http://www.mono-project.com/docs/about-mono/languages/cplusplus/ [23]: http://msdn.microsoft.com/en-us/library/ms235238.aspx [24]: http://stackoverflow.com/questions/20173189/managed-class-with-a-non-managed-member

Viewing all articles
Browse latest Browse all 706

Trending Articles



<script src="https://jsc.adskeeper.com/r/s/rssing.com.1596347.js" async> </script>