2006-02-01-01-class DLL
>> Site top >> weblog >> 月別アーカイブ >> 2006年02月のlog >> 2006-02-01-01-class DLL
最終更新日付:2006/02/01 01:00:00
class DLL
2006 年 02 月 01 日
仕事中、Windows エクスプローラを使用していたら、ちょっと間違えて懐かしいフォルダを開いてしまった。そこには、かれこれ5年前に書いた DLL 関数のラッパークラスのソースコードが。最近仕事に倦んでいるせいもあり、忙しいのにちょっとイジってみたりして。というわけでちょいと書いてみよう。
普通、Win32 SDK の世界では、直球勝負で DLL 関数を呼び出す場合、LoadLibrary( ) で DLL をロードし、GetProcAddress( ) で DLL 関数のアドレスを取得し使用、用済みになったら FreeLibrary( ) で開放...という段取りを踏む(もちろん他の方法もあるが)。ここで Sample.dll に以下の2つの関数 Foo( ), Bar( ) があるとすると、上記の方法なら以下のようなコードになる。あ、ちなみにコードは C++ スタイル。
typedef int (*FooT)( int, const char* ); typedef void (*BarT)( int ); HINSTANCE handle = ::LoadLibrary( "Sample.dll" ); FooT pFoo = static_cast<FooT>( ::GetProcAddress( handle, "Foo" ) ); BarT pBar = static_cast<BarT>( ::GetProcAddress( handle, "Bar" ) ); int ret = pFoo( 0, "test" ); pBar( ret ); ::FreeLibrary( handle );
まさにクラスでラップするためのサンプルのような状況だ。FreeLibrary( ) を呼び忘れることが考えられるし、アプリケーション全体でこの DLL を使用するのであれば handle を保持したり、FreeLibrary( ) を呼び出すタイミングや責任をどうするかという問題もある。取得した関数アドレスを、FreeLibrary( ) を呼び出した後で使用すれば簡単に破局が訪れるだろう。また、場合によっては typedef が大域に浮遊することも考えられる。そして、これらの問題のほとんどはクラスでラップしてやることで解決できる。たとえば、以下のように使用できるクラス SampleDLL があったらどうだろう。
SampleDLL theDLL; int ret = theDLL.Foo( 0, "test" ); theDLL.Bar( ret );
...つまり、DLL にまつわる API 呼出しは全てこの SampleDLL クラスの中に隠されているわけだ。クラスのコンストラクタ/デストラクタで DLL のロードや関数アドレスの取得、DLL の開放をやってくれるからミスは少なくとも局所化できる。SampleDLL::Foo( ) などを使用できるのはオブジェクトが存在している間だけだからその点でも安心だ。DLL が提供する関数とクラス定義は密接に関連するから、DLL 名ですらクラスの中に隠すことができる。そして面白いことに、このクラス SampleDLL にはメンバ関数 Foo( ) や Bar( ) は存在しないのだ。なんと、上記コードで使用されている Fooや Bar は、DLL 関数のアドレスを指す public な const 関数ポインタ、つまりデータメンバなのである...ま、こういったことを巧妙にやってくれるカラクリを作ったわけだ。5年前に。
で、5年経ってソースコードを見る...うぅむ、甘い。甘いぞ5年前の陰郎よ。以前にも書いたことだが、昔書いたコードに未熟さを感じるとき、陰郎は少し安心する。まだ自分は成長しているのだ...というわけで修正。作ったときもそう思っていたけれども、このカラクリは結構面白い。せっかくだから続きは後日書こう。そしてこの DLL ラッパークラス、そのうちに公開してみるとしよう。使う人がいるかどうかはわからないが。
コメント
このページのタグ
Page tag : 開発
Copyright(C) 2005-2021 project-enigma.
Generated by CL-PREFAB.