之前在這一篇有簡短提到過,沒想到事隔四五年又遇到要寫這樣程式的機會,順便整理一下吧。
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

