t69 c++cli ネイティブライブラリラッピング入門

65
わんくま同盟 東京勉強会 #69 C++/CLI ネイティブライブラリラッピン グ入門 暁 紫電

Upload: -

Post on 07-Jul-2015

2.634 views

Category:

Documents


0 download

TRANSCRIPT

Page 1: T69 c++cli ネイティブライブラリラッピング入門

わんくま同盟 東京勉強会 #69

C++/CLI

ネイティブライブラリラッピング入門

暁 紫電

Page 2: T69 c++cli ネイティブライブラリラッピング入門

わんくま同盟 東京勉強会 #69

自己紹介

• HN 暁 紫電

• Twitter @akatukisiden

• 年齢 25歳

• フリープログラマー

• 使用言語

C++、C++/CLI、C#

• 現在のお仕事

Kinect(OpenNI)、OpenCV、MIDI

Page 3: T69 c++cli ネイティブライブラリラッピング入門

わんくま同盟 東京勉強会 #69

マネージ コードとネイティブ コード相互運用テクノロジ

• P/Invoke

• COM

• C++/CLI

Page 4: T69 c++cli ネイティブライブラリラッピング入門

わんくま同盟 東京勉強会 #69

Platform Invoke (P/Invoke)

• DLLからC スタイルのネイティブ関数を呼び出す。

• ヘッダファイルの情報を

.NET側に用意する必要がある。

• .NET Frameworkの内部でよく使用されている

• 引数のマネージ←→ネイティブ変換コストに加え

一回の呼び出しでx86命令10~30個分の

オーバーヘッドが係る

• どんな関数でも正常に呼び出せるわけではない

Page 5: T69 c++cli ネイティブライブラリラッピング入門

わんくま同盟 東京勉強会 #69

COM相互運用

• I Unknown

• マネージ コードからCOMインターフェイスを使用、

またはマネージAPIを COMインターフェイスとして

公開する機能

• Office関連や、WinRTなどで使われている

• 時間コストはC++/CLIと同程度

Page 6: T69 c++cli ネイティブライブラリラッピング入門

わんくま同盟 東京勉強会 #69

C++/CLI

• Cヰ

• マネージ コードおよびネイティブ コードが混在するアセンブリを作成する

• P/Invokeとは違い、見た目は普通の

マネージオブジェクトにすることが可能

• おそらく、どんなクラス・関数でもラップ可能

Page 7: T69 c++cli ネイティブライブラリラッピング入門

わんくま同盟 東京勉強会 #69

今回は

画像処理ライブラリOpenCVのラップを通して

C++/CLIを用いた

.NETでのネイティブコードの利用について

紹介します。※ ヘッダファイルに宣言と定義、両方まとめて書いてい

ますが、実際は分けて書いてください

Page 8: T69 c++cli ネイティブライブラリラッピング入門

わんくま同盟 東京勉強会 #69

マネージ型

• class structの使い方はC++相当

• 値型・参照型はその前につけるvalue/refで決まる。

• 参照型のハンドルは型名の後ろに^をつけて表す

値・参照\デフォルト

アクセス指定子Public private

参照型 ref struct; ref class;

値型 value struct; value class;

Page 9: T69 c++cli ネイティブライブラリラッピング入門

わんくま同盟 東京勉強会 #69

矩形等のサイズを表す構造体CvSizeをラップする

Page 10: T69 c++cli ネイティブライブラリラッピング入門

わんくま同盟 東京勉強会 #69

Wrap1 最低限のラップ (CvSize)

public ref class CvSize{

public:CvSize(void){ ptr = new ::CvSize; }

~CvSize(){ this -> !CvSize(); }

!CvSize(){ delete ptr; }

internal:::CvSize* ptr;

};

Page 11: T69 c++cli ネイティブライブラリラッピング入門

わんくま同盟 東京勉強会 #69

Wrap1 最低限のラップ (CvSize)

• ref class

• ネイティブオブジェクトのポインタを

internalメンバとして持たせる。

• コンストラクタでオブジェクトを生成

• デストラクタ/ファイナライザで破棄

• デストラクタ(~Class())はDispose(true)相当

• ファイナライザ(!Class())はDispose(false) 相当

• ファイナライザは通常の関数として呼び出し可能

Page 12: T69 c++cli ネイティブライブラリラッピング入門

わんくま同盟 東京勉強会 #69

Wrap2 基本型メンバ変数の公開 (CvSize)

public ref class CvSize{

// ~~略~~public:

property int width{

int get(){ return ptr_->width;}void set( int value ){ ptr_->width = value; }

}property int height

{int get(){return ptr_->height;}

void set(int value){ptr_->height = value; }}

internal:::CvSize* ptr_

};

Page 13: T69 c++cli ネイティブライブラリラッピング入門

わんくま同盟 東京勉強会 #69

Wrap2 基本型メンバ変数の公開 (CvSize)

• メンバ変数はプロパティとして公開する

• Internalポインタを通してメンバ変数にアクセス

• 基本型はマネージ、ネイティブ間で互換性有り

Page 14: T69 c++cli ネイティブライブラリラッピング入門

わんくま同盟 東京勉強会 #69

OpenCV画像クラスIplImageをラップする

Page 15: T69 c++cli ネイティブライブラリラッピング入門

わんくま同盟 東京勉強会 #69

Wrap3 ポインタで管理するクラス(IplImage)

public ref class IplImage{

public:IplImage(CvSize^ size,int depth,int channels){ ptr = ::cvCreateImage(*size->ptr,depth,channels);}

~IplImage(){ this->!IplImage(); }

!IplImage(){

pin_ptr<::IplImage*> pin_Image = &ptr;::cvReleaseImage(pin_Image);

}internal:

::IplImage* ptr;};

Page 16: T69 c++cli ネイティブライブラリラッピング入門

わんくま同盟 東京勉強会 #69

Wrap3 ポインタで管理するクラス(IplImage)

• 独自の生成関数、解放関数を持ち、

インスタンスはポインタで管理するクラス

• 生成・解放関数自体はコンストラクタ、

ファイナライザ内で呼び出す。

• ダブルポインタを引数に取る関数(解放関数)は

そのままではガベコレでアドレスが変わる

可能性があるというエラーが発生するので

pin_ptr<T*>でアドレスを固定する

Page 17: T69 c++cli ネイティブライブラリラッピング入門

わんくま同盟 東京勉強会 #69

画像ファイル読み込み関数cvLoadImageを

コンストラクタとしてラップ

Page 18: T69 c++cli ネイティブライブラリラッピング入門

わんくま同盟 東京勉強会 #69

Wrap4 文字列変換(cvLoadImage)public ref class IplImage{

// ~~略~~public:

IplImage(System::String^ str, int iscolor){

const char* chars = (const char*)System::Runtime::InteropServices::Marshal

::StringToHGlobalAnsi(str).ToPointer();

this->ptr = ::cvLoadImage(chars ,iscolor);

System::Runtime::InteropServices::Marshal::FreeHGlobal(System::IntPtr((vo

id*)chars));}

// ~~略~~};

Page 19: T69 c++cli ネイティブライブラリラッピング入門

わんくま同盟 東京勉強会 #69

Wrap4 文字列変換(cvLoadImage)

• System.Stringからchar*に変換

• マネージ・アンマネージの変換用の関数をまとめたMarshalクラスのメンバを使用

• IntPtr Marshal::StringToHGlobalAnsi(string);

String の内容をアンマネージ メモリにコピーし、

コピー時に ANSI 形式に変換します。

• void Marshal::FreeHGlobal(IntPtr);

アンマネージメモリから割り当てられたメモリを

解放します。

Page 20: T69 c++cli ネイティブライブラリラッピング入門

わんくま同盟 東京勉強会 #69

しきい値処理関数cvThresholdをラップする

Page 21: T69 c++cli ネイティブライブラリラッピング入門

わんくま同盟 東京勉強会 #69

Wrap5 関数のラップ(cvThreshold)public ref class IplImage{// ~~略~~

double cvThreshold( IplImage^ src, IplImage^ dst,double threshold, double max_value, int

threshold_type ){

return ::cvThreshold(src->ptr, dst->ptr,threshold, max_value,

threshold_type);}

};

Page 22: T69 c++cli ネイティブライブラリラッピング入門

わんくま同盟 東京勉強会 #69

Wrap5 関数のラップ(cvThreshold)

• オブジェクトを引数に取るものは

内部ポインタを(必要なら*をつけて)渡す。

• 基本型引数はそのまま渡せる。

Page 23: T69 c++cli ネイティブライブラリラッピング入門

わんくま同盟 東京勉強会 #69

とりあえず一回実行してみる

※ 表示に必要な関数は予めラップ済み

Page 24: T69 c++cli ネイティブライブラリラッピング入門

わんくま同盟 東京勉強会 #69

表示用関数郡

using namespace System::Runtime::InteropServices;public ref class GUI{

public:static int cvNamedWindow( System::String^ str, int flags ){

const char* chars = (const char*)Marshal::StringToHGlobalAnsi(str).ToPointer();

int r = ::cvNamedWindow(chars,flags);Marshal::FreeHGlobal(System::IntPtr((void*)chars));

return r;}

Page 25: T69 c++cli ネイティブライブラリラッピング入門

わんくま同盟 東京勉強会 #69

表示用関数

static void cvDestroyWindow( System::String^ str){

const char* chars = (const char*)Marshal::StringToHGlobalAnsi(str).ToPointer();

::cvDestroyWindow( chars );Marshal::FreeHGlobal( System::IntPtr((void*)chars));

}

static void cvShowImage( System::String^ name,IplImage^ image){

const char* chars = (const char*)Marshal::StringToHGlobalAnsi(name).ToPointer();

::cvShowImage( chars ,image->ptr);Marshal::FreeHGlobal( System::IntPtr((void*)chars));

}static int cvWaitKey(int delay){ return ::cvWaitKey(delay); }

};

Page 26: T69 c++cli ネイティブライブラリラッピング入門

わんくま同盟 東京勉強会 #69

実行コード C#

class Program{

static void Main( string[] args){

GUI.cvNamedWindow( "window" , 1);

IplImage loadedImage = new IplImage( "wankuma.png” , 0);

GUI.cvShowImage( "window” , loadedImage);GUI.cvWaitKey(0);

CvSize size = new CvSize();size.width = loadedImage.width;size.height = loadedImage.height;IplImage img2 = new IplImage(size, loadedImage.depth,

loadedImage.nChannels );

Page 27: T69 c++cli ネイティブライブラリラッピング入門

わんくま同盟 東京勉強会 #69

実行コード C#

IplImage.cvThreshold(loadedImage, img2, 205, 255, 0);

GUI.cvShowImage( "window" , img2);GUI.cvWaitKey(0);

GUI.cvDestroyWindow( "window" );}

}

Page 28: T69 c++cli ネイティブライブラリラッピング入門

わんくま同盟 東京勉強会 #69

Page 29: T69 c++cli ネイティブライブラリラッピング入門

わんくま同盟 東京勉強会 #69

Page 30: T69 c++cli ネイティブライブラリラッピング入門

わんくま同盟 東京勉強会 #69

Page 31: T69 c++cli ネイティブライブラリラッピング入門

わんくま同盟 東京勉強会 #69

二値画像から輪郭とその外接矩形を取得する

Page 32: T69 c++cli ネイティブライブラリラッピング入門

わんくま同盟 東京勉強会 #69

Wrap6

輪郭クラスはメモリストレージCvMemStorage内に確保されるのでまずはCvMemStorageをラップ

Page 33: T69 c++cli ネイティブライブラリラッピング入門

わんくま同盟 東京勉強会 #69

Wrap6 メモリストレージ CvMemStorage

public ref class CvMemStorage{

public:CvMemStorage( int block_size){ ptr_ = ::cvCreateMemStorage(block_size); }

~CvMemStorage() { this->!CvMemStorage();}

!CvMemStorage(){

pin_ptr< ::CvMemStorage* > p = &(this->ptr_ );::cvReleaseMemStorage( p ) ;

}static void cvClearMemStorage(CvMemStorage^ storage){ ::cvClearMemStorage(storage->ptr_ ); }

internal:::CvMemStorage* ptr_;

};

Page 34: T69 c++cli ネイティブライブラリラッピング入門

わんくま同盟 東京勉強会 #69

• コンストラクタでストレージ生成

• ファイナライザで全解放

• 割り当て済みストレージの解放関数

– void cvClearMemStorage(CvMemStorage^ storage);

Wrap6 メモリストレージ CvMemStorage

Page 35: T69 c++cli ネイティブライブラリラッピング入門

わんくま同盟 東京勉強会 #69

wrap7

輪郭クラスCvContourは生成・破棄の方法が特殊なので

先にそのメンバ変数rect(CvRect型)をラップし

プロパティとして公開する

Page 36: T69 c++cli ネイティブライブラリラッピング入門

わんくま同盟 東京勉強会 #69

Wrap7 複合型メンバ変数をプロパティとして公開(CvContour::rect)

Class AとそのメンバBをラップしたものが

Page 37: T69 c++cli ネイティブライブラリラッピング入門

わんくま同盟 東京勉強会 #69

Wrap7 複合型メンバ変数をプロパティとして公開(CvContour::rect)

ClassAのラッパーがBのラッパーをメンバに持つように見えるようにする必要がある

Page 38: T69 c++cli ネイティブライブラリラッピング入門

わんくま同盟 東京勉強会 #69

Wrap7 複合型メンバ変数をプロパティとして公開(CvContour::rect)

public ref class CvContour{

public:// ~~略~~property CvRect^ rect{

CvRect^ get(){

return gcnew CvRect(&ptr_->rect);}void set(CvRect^ value){

*ptr_->rect = *(value->ptr_);}

}internal:

::CvContour* ptr_;};

Page 39: T69 c++cli ネイティブライブラリラッピング入門

わんくま同盟 東京勉強会 #69

Wrap7 複合型メンバ変数をプロパティとして公開(CvContour::rect)

public ref class CvRect{

public:// ~~略~~CvRect(){

noalloc_ = false;this-> ptr_ = new ::CvRect;

}

CvRect( ::CvRect* pRect){

noalloc_ = true;this->ptr_ = pRect;

}

~CvRect(){ this->!CvRect();}

!CvRect(){

if(!noalloc_){

delete ptr_;}this->ptr_ = nullptr;

}private:

bool noalloc_ ;

Internal:

::CvRect* ptr_;

}

Page 40: T69 c++cli ネイティブライブラリラッピング入門

わんくま同盟 東京勉強会 #69

Wrap7 複合型メンバ変数をプロパティとして公開(CvContour::rect)

• プロパティのgetterではポインタを受け取るコンストラクタを用いて、ラッパーオブジェクトを作成(gcnew)する。

• ポインタを受け取るコンストラクタで初期化した場合は非破壊フラグを立て、ファイナライザでdeleteしないようにする。

• setterではvalue側の内部ポインタの指す値をコピーする。

Page 41: T69 c++cli ネイティブライブラリラッピング入門

わんくま同盟 東京勉強会 #69

wrap8

輪郭スキャンクラスCvContourScanner

輪郭スキャン関数群cvStartFindContours

cvFindNextContour

cvEndFindContours

のラップ

Page 42: T69 c++cli ネイティブライブラリラッピング入門

わんくま同盟 東京勉強会 #69

Wrap8 輪郭スキャン関連

使い方が複雑なのでまずC++側でどのように使うかを確認

Page 43: T69 c++cli ネイティブライブラリラッピング入門

わんくま同盟 東京勉強会 #69

IplImage img_th = 閾値処理後の画像CvContourScanner scanner = cvStartFindContours(img_th, storage);

CvContour* contour;do{

contour = reinterpret_cast< CvContour*>( cvFindNextContour(scanner) );

if(contour != nullptr){

CvRect rect = contour->rect; }

}while (contour != nullptr);contour = reinterpret_cast<CvContour*>(cvEndFindContours(&scanner));cvClearMemStorage(contour->storage);

Wrap8 輪郭スキャン関連(C++)

Page 44: T69 c++cli ネイティブライブラリラッピング入門

わんくま同盟 東京勉強会 #69

• CvContourScanner は_CvContourScanner*のtypedef

• CvContourScannerの定義はヘッダファイルにない

• cvStartFindContours(img,storage)は閾値処理済み画像と、

輪郭オブジェクトの確保につかうメモリストレージを引数にとり

CvContourScanner を生成

• cvFindNextContourは、輪郭を一つ取得

• cvEndFindContoursはCvContourScanner を破棄し、

全部の輪郭データを取得 メンバ変数をたどって別の輪郭の取得も可能

• cvClearMemStorage(storage)で輪郭データの解放+メモリストレージにメモリを返還

• cvFindNextContour,cvEndFindContourの戻り値は

オブジェクトの先頭のメモリ構造を同じにすることで行う疑似継承

における 疑似基底クラス

Wrap8 輪郭スキャン関連(C++)

Page 45: T69 c++cli ネイティブライブラリラッピング入門

わんくま同盟 東京勉強会 #69

Wrap8 輪郭抽出関数のラップ

public ref class CvContourScanner{

public:static const int DEFAULT_HEADER_SIZE = sizeof( ::CvContour);

CvContourScanner(IplImage^ image,CvMemStorage^ storage,int header_size, int mode, int method,CvPoint^ offset)

{ptr_ =::cvStartFindContours(image->ptr_,storage->ptr_,

header_size,mode,method,*offset->ptr_);}

static CvContourScanner^ cvStartFindContours(IplImage^ image,CvMemStorage^ storage, int header_size,

int mode, int method,CvPoint^ offset){

return = gcnew CvContourScanner(image,storage,header_size,mode,method,offset);

}

Page 46: T69 c++cli ネイティブライブラリラッピング入門

わんくま同盟 東京勉強会 #69

Wrap8 輪郭抽出関数のラップ

CvContour^ cvFindNextContour(){

::CvContour* contour= reinterpret_cast< ::CvContour*>( ::cvFindNextContour(this->ptr_) );

if(contour != nullptr){

return gcnew CvContour(contour);}else{

return nullptr;}

}

static CvContour^ cvFindNextContour(CvContourScanner^ scanner){

return scanner->cvFindNextContour();}

Page 47: T69 c++cli ネイティブライブラリラッピング入門

わんくま同盟 東京勉強会 #69

Wrap8 輪郭抽出関数のラップ

CvContour^ cvEndFindContours(){

pin_ptr< ::_CvContourScanner* > pp = &(this->ptr_);::CvContour* ptr = reinterpret_cast< ::CvContour*>

(::cvEndFindContours(pp));pp = nullptr; this->ptr_ = nullptr;CvContour^ contour = gcnew CvContour();contour->ptr_ = ptr;return contour;

}

static CvContour^ cvEndFindContours(CvContourScanner^ scanner){

return scanner->cvEndFindContours();}

Page 48: T69 c++cli ネイティブライブラリラッピング入門

わんくま同盟 東京勉強会 #69

Wrap8 輪郭抽出関数のラップ

~CvContourScanner(){

this->!CvContourScanner();}!CvContourScanner(){

if(!noalloc_){

if(this->ptr_ != nullptr){

pin_ptr< ::_CvContourScanner* > pp = &(this->ptr_);::CvContour* contour = reinterpret_cast< ::CvContour*>

( ::cvEndFindContours(pp) );::cvClearMemStorage(contour->storage);this->ptr_ = nullptr;

}}

}

Page 49: T69 c++cli ネイティブライブラリラッピング入門

わんくま同盟 東京勉強会 #69

Wrap8 輪郭抽出関数のラップ(C++/CLI)

private:bool noalloc_;

internal:_CvContourScanner* ptr_;

}

struct _CvContourScanner{};

Page 50: T69 c++cli ネイティブライブラリラッピング入門

わんくま同盟 東京勉強会 #69

Wrap8 輪郭抽出関数のラップ(C++/CLI)

public ref class CvContour{

public:CvContour(){ noalloc_ = false; this->ptr_ = nullptr; }

~CvContour() {this->!CvContour();}!CvContour(){

if(!noalloc_) { ::cvClearMemStorage(ptr_->storage); }}

private:bool noalloc_;

internal:CvContour( ::CvContour* ptr){noalloc_ = true; this->ptr_ = ptr; }::CvContour* ptr_;

};

Page 51: T69 c++cli ネイティブライブラリラッピング入門

わんくま同盟 東京勉強会 #69

輪郭抽出関数のラップ

• CvContourScannerがヘッダファイルに定義がないので、

自分で空の構造体を作成する。

(ポインタのサイズが分かれば正常に動作するはず)

• CvContourScannerオブジェクトはcvStartFindContours()で作成し、cvEndFindContours()で破棄する

cvEnd~を呼び忘れても良いように、データが破棄されていなければ、

ファイナライザで呼び出す。

• 輪郭データの破壊はcvEndFindContours()で返されるオブジェクト(全輪郭の代表に)に対して::cvClearMemStorage()を呼び出すことで行う。(ファイナライザで呼び出す。)

• cvFindNextContourの戻り値の輪郭データは開放してはいけないので

cvFindNext~では非破壊コンストラクタ、

cvEndFind~では通常のコンストラクタで輪郭オブジェクトを

作成する(cvContour)

Page 52: T69 c++cli ネイティブライブラリラッピング入門

わんくま同盟 東京勉強会 #69

もう一回実行してみる

Page 53: T69 c++cli ネイティブライブラリラッピング入門

わんくま同盟 東京勉強会 #69

輪郭・矩形 描画関連 (C++/CLI)

public ref class IplImage{

public:// ~~略~~

static void cvDrawContours(IplImage^ img, CvContour^ contour,CvScalar^ external_color,CvScalar^ hole_color,

int max_level, int thickness ,int line_type, CvPoint^ offset){::cvDrawContours(img->ptr_,reinterpret_cast<CvSeq*>

(contour->ptr_), *external_color->ptr_, *hole_color->ptr_,max_level,thickness,line_type, *offset->ptr_);

}static void cvRectangleR(IplImage^ img, CvRect^ r,

CvScalar^ color,int thickness, int line_type, int shift){

::cvRectangleR(img->ptr_,*r->ptr_,*color->ptr_,thickness,line_type,shift);

}};

Page 54: T69 c++cli ネイティブライブラリラッピング入門

わんくま同盟 東京勉強会 #69

続・実行コード C#

class Program{

static void Main(string[] args){

// ~~略~~CvMemStorage storage = new CvMemStorage(0);CvContourScanner scanner = new CvContourScanner

(img2,storage,CvContourScanner.DEFAULT_HEADER_SIZE,1,2,new CvPoint(0,0));

List<CvRect> list = new List<CvRect>();CvContour scanningContour = null;

Page 55: T69 c++cli ネイティブライブラリラッピング入門

わんくま同盟 東京勉強会 #69

続・実行コード C#do{

scanningContour = scanner.cvFindNextContour();if (scanningContour!= null){

list.Add(scanningContour.rect);}

}while (scanningContour != null);

CvContour endContour = scanner.cvEndFindContours();IplImage.cvDrawContours(img2,endContour,new CvScalar(64,64,64,64),

new CvScalar(255,255,255,255), 1,2,8, new CvPoint(0, 0));

GUI.cvShowImage( "window" , img2);GUI.cvWaitKey(0);

Page 56: T69 c++cli ネイティブライブラリラッピング入門

わんくま同盟 東京勉強会 #69

続・実行コード C#

foreach(CvRect r in list){

IplImage.cvRectangleR(img2, r, new CvScalar(128, 128,128,128), 2, 8, 0);

}

endContour.Dispose();storage.Dispose();

GUI.cvShowImage( "window" , img2);GUI.cvWaitKey(0);

img2.Dispose();GUI.cvDestroyWindow( "window" );

}};

Page 57: T69 c++cli ネイティブライブラリラッピング入門

わんくま同盟 東京勉強会 #69

Page 58: T69 c++cli ネイティブライブラリラッピング入門

わんくま同盟 東京勉強会 #69

Page 59: T69 c++cli ネイティブライブラリラッピング入門

わんくま同盟 東京勉強会 #69

Page 60: T69 c++cli ネイティブライブラリラッピング入門

わんくま同盟 東京勉強会 #69

Page 61: T69 c++cli ネイティブライブラリラッピング入門

わんくま同盟 東京勉強会 #69

Page 62: T69 c++cli ネイティブライブラリラッピング入門

わんくま同盟 東京勉強会 #69

まとめ

Page 63: T69 c++cli ネイティブライブラリラッピング入門

わんくま同盟 東京勉強会 #69

まとめ

• ネイティブオブジェクトはポインタで管理しコンストラクタでnew,ファイナライザでdeleteする

• ポインタ等の露出する部分はinternalにして

外部から見えないようにする。

• メンバ変数はプロパティとして公開

• ダブルポインタはpin_ptrでアドレスを固定

• char*↔System.String等はMarshalクラスで変換

Page 64: T69 c++cli ネイティブライブラリラッピング入門

わんくま同盟 東京勉強会 #69

まとめ

• 複合型メンバ変数は、ポインタを受け取るコンストラクタを使い、マネージド型(ラッパークラス)のプロパティとして公開する。解放は親が解放される事で行われるので、ファイナライザで開放しないようにする。

• マネージドオブジェクトが消滅するときラップしたネイティブオブジェクトも解放(delete)してよいのか注意し、

• よくない場合は、コンストラクタでフラグを立てるなどの方法で、ファイナライザでの解放を防ぐ

Page 65: T69 c++cli ネイティブライブラリラッピング入門

わんくま同盟 東京勉強会 #69

ご清聴ありがとうございました