ホーム ] PC技術/システム技術 ] VB.NETプログラミング ] VB.NETコンポーネント ] VC++コンポーネント ] 共通事項 ] インフォメーション ]

上へ
C++ネイティブDLL
試作第1号
試作第2号

C++コンポーネント

試作第1号( ImageProcessing.dll)

最終更新日:2007/04/28  修正

●概要

 確認のため、空間フィルタを実行するDLLを開発し、その機能と実行速度を確認した。

●仕様

○名称

  ImageProcessing.dll

○機能

  画像の一次変換(Convert)と空間フィルタ(SpatialFilter)を行う。

○入出力

・Convert

 原画を一次元バイト配列の参照で与え、変換係数(a, b) をDoubleで与える。結果は、原画配列に返す。

・SpatialFilter

 周辺を拡張された原画を一次元バイト配列の参照、結果を収める領域も、一次元バイト配列の参照で与える。フィルタ関数は、一次元Double配列で与える。フィルタ係数もDoubleで与える。その他、原画サイズ、フィルタサイズをIntegerで与える。

○ラッパ

 エンドプログラマには、C++を見せなく、VB.NETでラップし、マネージコードのクラスとして見せる。

●実例

・2007/3/24 バグ発見

 フィルタの試験をしていると不可解な現象が出た。メモリ領域外アクセスと言うもの。配列のサイズやインデックスをチェックしたが問題なし。現象が不安定であるが、どうもフィルタサイズに関係している。暫く悩んでしまった。調べているうちに、C++で、メモリ要求をしているが、この要求サイズはバイト単位であることに気づいた。要求はint配列なので、要求数を4倍して解決。おはずかしい。

 その後、C++では、メモリ要求は、malloc ではなく、new 演算子を使った方が良いと判明。new に変更。

・C++側関数定義

void ImageProcess::SpatialFilter(unsigned char a[], unsigned char b[], double Filter[], double cf, double bs, int w, int h, int x, int y)

注意:特に断らない限り、char型は、符号付バイトとなる。画像の画素を扱う場合、符号付では正しく処理できないので、unsigned char とする必要がある。

○VB側

・DLL宣言

 <C++Exportの場合>筆者の従来の方法

Friend Declare Sub cppSpatialFilter Lib "P:\VC.NET2005\DllSrc\ImageProcessing\Release\ImageProcessing.dll" _
Alias "?SpatialFilter@ImageProcess@ImageProcessing@@SAXQAE0QANNNHHHH@Z" _
(ByRef Src As Byte, ByRef Dst As Byte, ByVal Filter() As Double, ByVal Cf As Double, ByVal Base As Double, ByVal W As Integer, ByVal H As Integer, ByVal X As Integer, ByVal Y As Integer)

 VBでは、DLL宣言で、DLLの場所を絶対パスにしている。これにより、開発中は、C++側の最新オブジェクトを常に参照できる。完成すれば、相対パスにすれば良い。

 予測不可能な内部関数名は、関数のシグネチャが変更されない限り、同じ文字列が維持されるようであるので、関数名、引数などを最初に注意深く決めておけば、Alias のメンテは楽になる。

 <DEFファイルの場合>筆者の現在の方法

Friend Declare Sub cppSpatialFilter Lib "・・・・・・\ImageProcessing\Release\ImageProcessing.dll" _
(ByRef Src As Byte, ByRef Dst As Byte, ByVal Filter() As Double, ByVal Cf As Double, ByVal Base As Double, ByVal W As Integer, ByVal H As Integer, ByVal X As Integer, ByVal Y As Integer)

 DEFファイルは、C++コンパイラで外部名と内部名の整合性が検査されている。また、dllファイルにDEFファイルの定義が埋め込まれているので、VB側での開発時や実行にはDEFファイルは不要である。やはりこちらの方がはるかに楽となる。

・関数呼び出し

 cppSpatialFilter(BBEx(0), Dst(0), Filter, Coef, Base, W, H, N, M)

 配列の参照渡しであるが、実際には、その配列の先頭要素を記述する。

●結果

○機能確認

 VBによる空間フィルタと同じ結果を得られた。

○処理時間実測

 試作したDLLを使って、空間フィルタの処理時間を計測した。下図のようになった。

 VB                    :純粋のVB(Get/SetPixelメソッド)のみで処理した場合
 VBマーシャル   :マーシャルによる配列転送の場合
 VB + Cpp          :マーシャルによる配列転送に加え、C++によるカーネル処理を行った場合

 VBの処理時間の1/3程度に改善された。ここでのVB処理時間は、元々、かなり頑張った値(巷で紹介されている、VBのGet/SetPixelメソッドによる画像処理・・・などの約十倍以上の速度)であるが、更にその3倍の速度となった訳である。

 この試験では、VBによる処理部分は、通り一遍の処理のみであり、C++の恩恵はあまり無い部分であると考えられるので、VBとC++ネイティブのコラボとしての最善値と思われる。C++ネイティブの支援は有効と思う。