2016-01-06 114 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); } } 
相關問題