2016-01-06 149 views
0

嗨,大家好,我在unity3d pro上遇到了一些问题,也许有人在使用DLL本机插件时可以了解我做错了什么。从Unity3d调用本机DLL的最佳方式是什么?

开始我会解释我的目标是什么。我有一个来自西门子PLCSim软件的COM对象,我已经使用Visual Studio正常工作。以下是测试代码。

namespace WindowsFormsApplication1 
{ 
    public partial class Form1 : Form 
    { 
     public S7PROSIMLib.S7ProSim PLCSimConn = new S7PROSIMLib.S7ProSim(); 

     public Form1() 
     { 
      InitializeComponent(); 
     } 

     private void button_Connect_Click(object sender, EventArgs e) 
     { 
      PLCSimConn.Connect(); 
      label_CPUState.Text = PLCSimConn.GetState(); 
      label_ScanMode.Text = PLCSimConn.GetScanMode().ToString(); 
     } 
    } 
} 

我创建了一个unity3d项目来测试它。我将dll导入到我的资产中,并且可以从我的c#脚本中调用S7PROSIMLib的方法和实例。 COM API这里,https://cache.industry.siemens.com/dl/files/855/1139855/att_29424/v1/S7WSPSCB.pdf

using UnityEngine; 
using System.Collections; 
using System.Runtime.InteropServices; 
using S7PROSIMLib; 

public class TestNative : MonoBehaviour { 

    public S7ProSimClass ps; 

    // Use this for initialization 
    void Start() { 

     ps = new S7ProSimClass(); 
     ps.Connect(); 
     Debug.Log (ps.GetState()); 

    } 

} 

现在在运行时,我得到如下:

收到COMException

System.Runtime.InteropServices.Marshal.ThrowExceptionForHR (Int32 errorCode) (at /Users/builduser/buildslave/mono-runtime-and-classlibs/build/mcs/class/corlib/System.Runtime.InteropServices/Marshal.cs:1031) 
System.__ComObject.Initialize (System.Type t) (at /Users/builduser/buildslave/mono-runtime-and-classlibs/build/mcs/class/corlib/System/__ComObject.cs:103) 
(wrapper remoting-invoke-with-check) System.__ComObject:Initialize (System.Type) 
Mono.Interop.ComInteropProxy.CreateProxy (System.Type t) (at /Users/builduser/buildslave/mono-runtime-and-classlibs/build/mcs/class/corlib/Mono.Interop/ComInteropProxy.cs:108) 
System.Runtime.Remoting.RemotingServices.CreateClientProxyForComInterop (System.Type type) (at /Users/builduser/buildslave/mono-runtime-and-classlibs/build/mcs/class/corlib/System.Runtime.Remoting/RemotingServices.cs:588) 
System.Runtime.Remoting.Activation.ActivationServices.CreateProxyForType (System.Type type) (at /Users/builduser/buildslave/mono-runtime-and-classlibs/build/mcs/class/corlib/System.Runtime.Remoting.Activation/ActivationServices.cs:234) 
TestNative.Start() (at Assets/Scripts/TestNative.cs:13) 

我看过的unity3d插件教程https://www.youtube.com/watch?v=DfRYLwG1Bug这不叫第三方DLL。

我已阅读以下内容:https://msdn.microsoft.com/en-us/library/ms973872.aspx在非托管和托管DLL上有很多很好的信息。

基于从上面的链接下面的代码片段:

调用COM API的 有两种方法可以从托管代码调用COM组件:通过COM互操作(在所有管理语言),或通过C++互操作(可用C++提供)。 对于调用OLE自动化兼容的COM组件,建议使用COM互操作。 CLR将负责COM组件激活和参数封送。

对于基于接口定义语言(IDL)调用COM组件,建议使用C++ interop。 C++层可以非常简洁,其余的托管代码可以用任何托管语言编写。 COM互操作依赖类型库中的信息来进行正确的互操作调用,但类型库通常不包含IDL文件中存在的所有信息。使用C++ interop通过允许直接访问这些COM API来解决这个问题。

我相信我已经在上面的unity c#脚本中显示了COM interop。这并不奏效。我的其他选择是通过C++互操作,但我还没有找到任何在线的例子。大多数示例都很简单,无需调用COM对象或任何其他第三方DLL。如果有人能以正确的方式指导我,我将不胜感激。基本上归结为什么是最好的方式去做这件事,用最少的方法重写?谢谢!

编辑1:我在YouTube上观看了这段视频,看看是否有人开始工作,但我一直没有得到他的回复。至少我知道它应该在unity3d上工作。 https://www.youtube.com/watch?v=EGFMjUJN7ZU

编辑2:Unity3d - Failed to load 'Assets/Plugins/QCARWrapper.dll'将尝试使用32位编辑器,因为这篇文章建议。

+0

@FᴀʀʜᴀɴAɴᴀᴍ我也看了这个位置https://msdn.microsoft.com/en-us/library/42b9ea93%28v=vs.110%29.aspx ?cs-save-lang = 1&cs-lang = csharp#code-snippet-1我可能误解了文献。那么这是否意味着我需要创建一个DLL来调用我的第三方DLL中的方法签名?你知道任何在线的好例子吗? – kodaman

+0

一点,考虑无处不在的Prime31插件 – Fattie

+0

@joeblow这些插件都不涉及我正在做的事情。尽管感谢您的评论。 – kodaman

回答

0

对于任何可能需要此帮助的人。西门子PLCSim COM类型库仅适用于32位Unity编辑器。

经过大量的试验和错误,这个解决方案实际上非常简单,还有更多的阅读方式可以通过论坛进行阅读。我用tlbimp。exe来生成一个类型库DLL,然后我把它放到assets/plugins文件夹中,同时注意在unity3d编辑器属性中新的DLL被视为托管代码。请注意,这个特定的DLL在64位Unity编辑器上不起作用,并且它抛出了一个COMException异常。然而,新的类型库DLL在32位Unity编辑器中工作正常,我想在DLL的某处有一条指令只能在32位工作。

我在这里记录了一个存储库中的所有内容https://github.com/fredz0003/myS7ProSimLib我还放置了托管的DLL以供将来使用,所以您不会去遇到麻烦。

下面是一个示例代码:

using UnityEngine; using myS7ProSimLib; 

public class TestNative : MonoBehaviour { 

    /* 
    * Used tlbimp.exe to generate library DLL 
    * place new generated DLL on assets/plugins 
    * also note that the DLL is treated as managed code 
    */ 
    public S7ProSimClass ps; 
    public bool input_0_0; 


    void Start() { 
     ps = new S7ProSimClass(); 

     ps.Connect(); 
     print("State " + ps.GetState()); 
     ps.SetScanMode(ScanModeConstants.ContinuousScan); 

     // Here we pass the ref as an obj, since WriteInputPoint method 
     // can take bit, word, dwords, as addresses ref obj can take the 
     // for of bool, int, float, etc. 
     object refInput0_0 = input_0_0; 

     ps.WriteInputPoint(0, 0, ref refInput0_0); } } 
相关问题