之前在這一篇有簡短提到過,沒想到事隔四五年又遇到要寫這樣程式的機會,順便整理一下吧。
Using .Net dll (class library) in *MANAGED* C++ program
如果是managed C++,那其實只要把.Net dll (class library)加入 reference 就可以了。(如下面兩張圖)
而.Net dll (class library)不需要多做什麼處理,就跟寫給其他.Net程式用的寫法即可。
namespace NMASNG { public class sng { public sng() { } public string _HDD() { char[] _ret; string tmp = "this is test"; return tmp; } public string _BaseBoard() { return "haha"; } public int _gInt() { return 10; } } }
比較不一樣的是在 C++ 這邊的寫法
using namespace NMASNG; using namespace std; #include <msclr/marshal_cppstd.h> int _tmain(int argc, _TCHAR* argv[]) { NMASNG::sng^ p = gcnew NMASNG::sng(); int x = p->_gInt(); std::string xs =msclr::interop::marshal_as< std::string >( p->_HDD() ); cout << x << endl; cout << xs << endl; return 0; }
這樣子再編譯 c++ 程式的時候,.Net Framework 也會進來參一腳,意即編譯出來的 .exe 不是單純的 win32 程式...
Using .Net dll (class library) in *UN-MANAGED* C++ program
有些時候"純 win32"來開發程式還是有必要的,而在這樣的環境限制下,就不可能呼叫 .Net dll (class library),而必須用傳統的 Win32 COM DLL。
所以在撰寫 .Net Class library 時,就必需要建立 COM 物件介面。
using System.Runtime.InteropServices; namespace NMASNG { // Interface declaration. [Guid("47F555AC-AB17-437a-AF2C-9F869EC589C0")] public interface I_Nmasng { [DispId(1)] string _HDD(); [DispId(2)] string _BaseBoard(); [DispId(3)] int _gInt(); } [Guid("4605A8CD-B0D2-4766-A31B-8E51FF3928CE"), InterfaceType(ComInterfaceType.InterfaceIsIDispatch)] public interface I_Nmasng_Events { } // Interface implementation. [Guid("8ADEC2A9-FE99-4d11-8F34-5DB75D70F146"), ClassInterface(ClassInterfaceType.None), ComSourceInterfaces(typeof(I_Nmasng_Events))] public class sng : I_Nmasng { public sng() { } public string _HDD() { char[] _ret; string tmp = "this is test"; return tmp; } public string _BaseBoard() { return "haha"; } public int _gInt() { return 10; } } }
GUID 的產生方式,可以用guidgen.exe這個程式來產生。(如下面兩張圖)
(guidgen.exe 在 C:\Program Files (x86)\Microsoft Visual Studio 9.0\Common7\Tools 或類似路徑)
另外,要在project properties做如以下三張圖片的設定。其中 Build Events 裡頭的 Post-build 是為了幫助跟系統註冊 dll 檔案。而Register for COM interop的選項是為了產生出COM物件,而最重要的是要Sign the assembly。
在 Sign the assembly 時,需要有個 .snk 檔案來儲存 strong name key。這個 .snk 檔案的產生方式為執行
sn -k ooxx.snk
(sn.exe 在 C:\Program Files\Microsoft SDKs\Windows\v6.0A\Bin 或類似的路徑)
如此一來,build這個 project 會得到帶有 COM 介面的 Class Library (.dll 跟 .tlb 檔案)
在 c++ 程式中,則要寫成這樣
#import "C:\_eapple\Release\NMASNG.tlb" using namespace NMASNG; using namespace std; int _tmain(int argc, _TCHAR* argv[]) { NMASNG::I_NmasngPtr p(__uuidof(NMASNG::sng)); I_Nmasng *ptr = p; cout << ptr->_gInt() << endl; cout << ptr->_HDD() << endl; return 0; }
然而,compile出來的 .exe 可以順利執行是因為有 .dll 與 .tlb,更重要的是前面我們已經跟系統註冊過 dll 檔案了。所以,如果要把這個程式搬到其他電腦上面用,也需要重新註冊 dll,這部分我建議可以寫成 batch,或者是包安裝程式內,讓使用者在在安裝時就順便做dll註冊。
@echo off @regasm.exe /tlb /codebase YOUR_DLL_FILE.dll @YOUR_EXEC_FILE.exe