2007 | 01 | 02 | 03 | 04 | 05 | 06 | 07 | 08 | 09 | 10 | 12 |
2008 | 02 | 03 | 04 | 05 | 06 | 07 | 08 | 09 | 10 | 11 | 12 |
2009 | 01 | 02 | 03 | 04 | 05 | 06 | 07 | 08 | 09 | 10 | 11 | 12 |
2010 | 01 | 02 | 03 | 04 | 05 | 06 | 07 | 08 | 09 | 10 | 11 | 12 |
2011 | 01 | 03 | 04 | 05 | 06 | 07 | 08 | 09 | 10 | 11 | 12 |
2012 | 01 | 03 | 04 | 05 |
2007-03-13
■[C++][.NET][VisualStudio] C++/CLI + mono その2

http://d.hatena.ne.jp/ak11/20070306/p1
の続き。
結局のところ、CRTさえ使わなければ、C++/CLIのコードはmonoで動かすことが出来るようだ。
↓こんな感じのコードを書いて、 コンパイルオプションに/clr:pureと、リンクオプションに/nodefaultlib、/entry:mainを指定するのが基本となる。
int main(array<System::String^>^ args) { } #pragma warning(disable:4483) void __clrcall __identifier(".cctor")() {}
とはいえ、C++/CLIに限った話ではないが、VC++において、CRTを使用しないというのは、結構こまごまと制約がある。C/C++の標準関数やSTLなどが(ほとんど)使えないのは当然だが、他にも、グローバル変数(静的変数)の動的な初期化や、vtable絡みなどが引っかかる。
グローバル変数は元々多用するものでも無く、回避も簡単なので問題ないが、vtableの方は少し面倒。具体的には、vtableを持つクラス(1個以上の仮想関数を持つクラス)のコンストラクタやデストラクタの定義がC++/CLI側から見えてはいけない。
例えば、インターフェースクラスの宣言などでこんな書き方をする場合があるが、
class IHoge { public: virtual ~IHoge() {} // ここがダメ。 virtual void Hoge() = 0; };
これをC++/CLI側から#includeしたりすると、それだけでリンクエラーがいくつか出てしまう。C++標準ライブラリのヘッダなどを#includeしたときもこれに引っかかる事があるので注意が必要だ。
コンストラクタやデストラクタは、 virtual ~IHoge(); のように定義を伴わない宣言だけを書かなくてはならない。単にこれだとC++側に定義が必要になってしまうので、__cplusplus_cli などを利用して切り替えるといいかもしれない。
そして、それに絡むが、ネイティブのクラスを継承して仮想関数をオーバーライドする事が出来ない。そもそも/clr:pureを指定しているので、__clrcall以外の(__cdeclなどの)関数は定義出来ないのだが。
ただし、関数ポインタであれば、System::Runtime::InteropServices::UnmanagedFunctionPointerAttribute と System::Runtime::InteropServices::Marshal::GetFunctionPointerForDelegate を使うことで何とか作り出せる。
あとは、new/deleteも、使うなら自前で定義する必要がある。これはまぁ、System::Runtime::InteropServices::Marshal::AllocHGlobalでも使って適当に定義するだけでいいのだが。
void* operator new(size_t n) { return (void*)System::Runtime::InteropServices::Marshal::AllocHGlobal((int)n); } void operator delete(void* p) { if (p == 0) return; System::Runtime::InteropServices::Marshal::FreeHGlobal(System::IntPtr(p)); }
あと、これはあまり検証していないが、名前マングリングの関係で、ネイティブのDLLからimportする関数には、extern "C" が付いて無いと、monoで動かしたときにEntryPointNotFoundExceptionが発生するようだ。
__declspec(dllexport)によるクラスのエクスポートも多分動かないだろう。
