DynLib:DLLを作成および操作するためのライブラリ

画像 DynLibライブラリは、プロジェクトでモジュール間通信(EXE <-> DLL、DLL <-> DLL)を使用する開発者に便利なツールを提供し、コードの時間と量を大幅に削減します。

DynLibは不可欠な開発ツールになりました。 猫の下で結果を共有します。









従来のDLL実装アプローチの欠点

従来のアプローチ(実装)の主な欠点は次のとおりです。
  1. 名前空間を使用する能力の欠如
  2. 多数のユーティリティコードが必要です。
    • ライブラリの動的ロードを実装する場合;
    • 記述子(または他の暗黙的な構造)およびラッパークラスを使用して、クラスを通じてモジュール間相互作用を実装する場合。
    • エクスポートされた関数が例外をスローする可能性がある場合、エラーリターンメカニズムを実装するとき。
これらの問題は、DynLibライブラリを使用して解決されます!

DynLibの例



1.通常のDLLを使用する



チャレンジ。 ヘッダーファイルに表示されるインターフェイスを使用して、簡単な数学演算を実装するtest_lib.dllライブラリを動的に接続して使用します。
//========== test_lib.h ========== #pragma once extern "C" __declspec(dllexport) int __stdcall sum(int x, int y); extern "C" __declspec(dllexport) int __stdcall mul(int x, int y); extern "C" __declspec(dllexport) double __stdcall epsilon();
      
      





解決策。 次のヘッダーファイルを作成し、プロジェクトに接続する必要があります。

 //========== test_lib.hpp ========== #pragma once #include <dl/include.hpp> DL_NS_BLOCK(( test ) ( DL_C_LIBRARY( lib ) ( ( int, __stdcall, (sum), (int,x)(int,y) ) ( int, __stdcall, (mul), (int,x)(int,y) ) ( double,__stdcall, (epsilon), () ) ) ))
      
      



プリプロセッサは、DLLを動的にロードし、リストされたsummul、およびepsilon関数を含むtest :: libクラスを生成します。 DLLをアプリケーションに接続するには、提供されたヘッダーファイルtest_lib.hppをソースコードに含める必要があります。 次に、クラスtest :: libのオブジェクトを作成します。 エクスポートされたDLL関数へのアクセスは、「。」を通じて可能です または「->」。

 //========== exe.cpp ========== #include "test_lib.hpp" int main() { test::lib lib( "path_to/test_lib.dll" ); int s = lib->sum( 5, 20 ); int m = lib.mul( 5, 10 ); double eps = lib.epsilon(); return 0; }
      
      





2. calculator.dllライブラリーの作成



チャレンジ。 ライブラリcalculator.dllを作成します。これは、合計、2つの数値の積、平方根値を計算する必要があります。 ライブラリを動的にロードし、各関数を呼び出します。

解決策

 //========== calculator.hpp ========== #include <dl\include.hpp> DL_NS_BLOCK(( team ) ( DL_LIBRARY( calculator ) ( ( double, sum, (double,x)(double,y) ) ( double, mul, (double,x)(double,y) ) ( double, sqrt, (double,x) ) ) )) //========== calculator_dll.cpp ========== #include "calculator.hpp" struct calculator { static double sum( double x, double y ) { return x + y; } static double mul( double x, double y ) { return x * y; } static double sqrt( double x ) { return std::sqrt(x); } }; DL_EXPORT( team::calculator, calculator )
      
      





DLLを使用する

 //========== application.cpp ========== #include <iostream> #include "calculator.hpp" int main() { using namespace std; team::calculator calc( "calculator.dll" ); cout << "sum = " << calc.sum(10, 20) << endl; cout << "mul = " << calc.mul(10, 20) << endl; cout << "sqrt = " << calc.sqrt(25) << endl; return 0; }
      
      





3. calculator.dllライブラリーのアップグレード。 例外の使用。



チャレンジ。 入力値が正しくない場合、calculator.dllライブラリの平方根sqrt関数はエラーを返します。

解決策

 //========== calculator.hpp ========== #include <dl\include.hpp> DL_NS_BLOCK(( team ) ( DL_LIBRARY( calculator ) ( ( double, sqrt, (double,x) ) ) )) //========== calculator_dll.cpp ========== #include "calculator.hpp" struct calculator { static double sqrt( double x ) { if ( x < 0 ) throw std::invalid_argument( "   0" ); return std::sqrt( x ); } }; DL_EXPORT( team::calculator, calculator )
      
      







DLLを使用する

 //========== application.cpp ========== #include <iostream> #include <locale> #include "calculator.hpp" int main() { using namespace std; locale::global( locale("", locale::ctype) ); try { team::calculator calc( "calculator.dll" ); cout << "sqrt1 = " << calc.sqrt( 25 ) << endl; cout << "sqrt2 = " << calc.sqrt( -1 ) << endl; } catch (dl::method_error const& e) { cerr << "what: " << e.what() << endl; } return 0; } //==========   ==========
      
      



 sqrt1 = 5 what: exception 'class std::invalid_argument' in method 'sqrt' of class '::team::calculator' with message '   0'
      
      





4. shapes.dllライブラリの実装。 インターフェイスの使用。



チャレンジ。 幾何学的図形(正方形、長方形、円)を操作するためのshapes.dllライブラリを作成します。 すべての図は、図の中心の座標を見つけることができる共通のインターフェースをサポートする必要があります。

解決策

 //========== shapes.hpp ========== #include <dl/include.hpp> DL_NS_BLOCK(( shapes ) ( DL_INTERFACE(figure) ( ( char const*, name, ) ( double, center_x, ) ( double, center_y, ) ( void, center_xy, (double&,x)(double&,y) ) ) )) DL_NS_BLOCK(( shapes ) ( DL_LIBRARY(lib) ( ( shapes::figure, create_rectangle, (double,left)(double,top)(double,width)(double,height) ) ( shapes::figure, create_square, (double,left)(double,top)(double,size) ) ( shapes::figure, create_circle, (double,center_x)(double,center_y)(double,radius) ) ) )) //========== shapes_lib.cpp ========== #include "shapes.hpp" class rectangle { public: rectangle(double l, double t, double w, double h) : l_(l), t_(t), w_(w), h_(h) { if (w < 0) throw std::invalid_argument( "   " ); if (h < 0) throw std::invalid_argument( "   " ); } char const* name() { return "rectangle"; } double center_x() { return l_ + w_ / 2.; } double center_y() { return t_ + h_ / 2.; } void center_xy(double& x, double& y) { x = center_x(); y = center_y(); } private: double l_, t_, w_, h_; }; class square { public: square(double l, double t, double s) : l_(l), t_(t), s_(s) { if (s < 0) throw std::invalid_argument( "    " ); } char const* name() { return "square"; } double center_x() { return l_ + s_ / 2.; } double center_y() { return t_ + s_ / 2.; } void center_xy(double& x, double& y) { x = center_x(); y = center_y(); } private: double l_, t_, s_; }; class circle { public: circle(double x, double y, double r) : x_(x), y_(y), r_(r) { if (r < 0) throw std::invalid_argument( "   " ); } char const* name() { return "circle"; } double center_x() { return x_; } double center_y() { return y_; } void center_xy(double& x, double& y) { x = x_; y = y_; } private: double x_, y_, r_; }; struct shapes_lib { static shapes::figure create_rectangle( double l, double t, double w, double h ) { return dl::shared<rectangle>( l, t, w, h ); } static shapes::figure create_square( double l, double t, double s ) { return dl::shared<square>( l, t, s ); } static shapes::figure create_circle( double x, double y, double r ) { return dl::shared<circle>( x, y, r ); } }; DL_EXPORT( shapes::lib, shapes_lib ) //========== application.cpp ========== #include <iostream> #include "shapes_lib.hpp" void print_center( shapes::figure shape ) { std::cout << shape.name() << ": " << shape.center_x() << "-" << shape.center_y() << std::endl; } int main() { shapes::lib lib( "shapes.dll" ); print_center( lib.create_circle(10, 10, 10) ); print_center( lib.create_square(0, 0, 20) ); print_center( lib.create_rectangle(0, 5, 20, 10) ); return 0; }
      
      





ライブラリの接続方法



ライブラリはヘッダーファイルの形式で提供されます。 .libと.dllは必要ありません。 接続するには、次のディレクティブを追加します。

 #include <dl/include.hpp>
      
      





ライブラリアイテム



DynLibライブラリの多くのクラスとマクロは、互いに独立して別々に使用できます。



DL_BLOCK


他のすべてのマクロのコンテナとして機能します。

 DL_BLOCK ( // declarations )
      
      









DL_NS_BLOCK


他のすべてのマクロのコンテナとして機能します。 クラスの名前空間を作成します。
 DL_NS_BLOCK( (ns0, ns1, ns2 … )/* ,  10*/ ( // declarations ))
      
      





DL_EXPORTを除く以下で説明するマクロは、 DL_BLOCKまたはDL_NS_BLOCKに配置する必要があります



DL_C_LIBRARY
マクロの目的は、DLLの動的なロードと関数の自動インポートを実装する既製のクラスをユーザーに提供することです。 マクロは次のように表示されます。

 DL_C_LIBRARY(lib_class) ( /*functions*/ ( ret_type, call, (name, import_name), arguments ) )
      
      





DL_C_LIBRARYマクロによって生成されたクラスは、DLLの境界を越えて渡すことはできません

DL_RECORD


DL_RECORDマクロは、 モジュール間通信で使用するためのパックデータ構造を生成します。 さらに、マクロにリストされているすべての引数を使用してコンストラクターが作成されます。

 DL_RECORD( record_name ) ( /*fields*/ (type, name, =default_value) )
      
      





例:



 //========== some_exe.cpp ========== #include <dl/include.hpp> DL_BLOCK ( DL_RECORD( data ) ( ( int, x ) ( int, y, = 100 /*  */ ) ( int, z, = 200 /*  */ ) ) ) int main() { data v( 20 ); // x = 20, y = 100, z = 200 vx = 10; vy = vx; vz = 50; v = data( 5, 20, 30 ); data a( 1, 2, 3 ); return 0; }
      
      







DL_LIBRARY


DL_LIBRARYマクロは、いくつかのタスクを実行します。
  1. EXE(DLL)とDLL間のインターフェースの説明(ドキュメント)として機能します。
  2. ライブラリ関数を開発者に自動的にエクスポートするために必要な構造が含まれています。
  3. 指定されたインターフェイスでDLLをロードし、ユーザーがエクスポートされた関数にアクセスできるクラスを実装します。
  4. C ++例外の正しい使用を提供します。
      -DLL側のC ++例外の自動キャッチ。
    	   -DLLの境界を介して値を返し、例外の存在を通知します。
    	   -例外がDLLの側でキャッチされた場合の新しい例外の生成(例外の種類に関する説明と情報の復元)
    	
 DL_LIBRARY( name ) ( /*functions*/ ( ret_type, name, arguments ) )
      
      





DL_LIBRARYマクロによって生成されたクラスは、DLLの境界を越えて渡すことはできません。

マクロがどのように機能するかを示すために、次のヘッダーファイルを想像してください。
 //========== test1_lib.hpp ========== #pragma once #include <dl/include.hpp> DL_NS_BLOCK(( team, test ) ( DL_LIBRARY( lib ) ( ( int, sum, (int,x)(int,y) ) ( void, mul, (int,x)(int,y)(int&,result) ) ( double, epsilon, () ) ) ))
      
      





この説明は、DLL開発者がDL_EXPORTマクロを使用して関数をエクスポートするために使用します。 test1_lib.hppヘッダーファイルを接続することにより、ユーザーはDLLの操作をすぐに開始できます。

 //========== test1_exe.cpp ========== #include <test1_lib.hpp> int main() { team::test::lib lib( "test1.dll" ); int s = lib.sum( 5, 10 ); lib.mul( 5, 5, s ); double eps = lib->epsilon(); return 0; }
      
      





DL_EXPORT


DL_EXPORTマクロは、 DLL関数をエクスポートするように設計されています。

DL_EXPORTlib_classlib_impl_class DLL関数をエクスポートするには、以下を行う必要があります。
  1. クラス(構造)を作成します。
  2. インターフェイスからの各関数を静的として定義します。 関数のスコープはpublic :;でなければなりません
  3. DL_EXPORT(lib、impl)コンストラクトを記述して、関数をエクスポートします。
例として、DL_LIBRARY記述で定義されたtest1_lib.hppファイル内のインターフェースのDLL実装を想像してください。

 //========== test1_dll.cpp ========== #include "test1_lib.hpp" struct lib_impl { static int sum( int x, int y ) { return x + y; } static void mul( int x, int y, int& result ) { result = x + y; } static double epsilon() { return 2.0e-8; } }; DL_EXPORT( team::test::lib, lib_impl )
      
      





DL_INTERFACE


このマクロを使用すると、クラスインターフェイスを記述し、それを操作するラッパークラスをユーザーに提供できます。 ラッパークラスの実装により、C ++例外の正しい使用が保証されます。
  -DLL側のC ++例外の自動キャッチ。
	  -DLLの境界を介して値を返し、例外の存在を通知します。
	  -例外がDLLの側でキャッチされた場合の新しい例外の生成(例外の種類に関する説明と情報の復元)
	
このマクロによって生成されたラッパークラスは、このインターフェイスを実装するオブジェクトの所有権を共有しています。 共有所有権は、リンクカウントメカニズムによって提供されます。 ラッパークラスのオブジェクトをコピーする場合、参照カウンターを増やすために内部関数が呼び出され、破棄される場合、参照カウンターを減らすために内部関数が呼び出されます。 カウンターが0に達すると、オブジェクトは自動的に削除されます。 インターフェイスメソッドへのアクセスは「。」を介して または「->」。

DynLibライブラリは、EXE境界(DLL)<-> DLLでのインターフェイスクラスの安全な使用を保証します



 DL_INTERFACE( interface_class ) ( /*methods*/ ( ret_type, name, arguments ) )
      
      



例:

 DL_NS_BLOCK(( example ) ( DL_INTERFACE( processor ) ( ( int, threads_count, () ) ( void, process, (char const*,buf)(std::size_t,size) ) ) ))
      
      





使用法:

  example::processor p; p =… // .  dl::shared  dl::ref int tcount = p->threads_count(); p.process(some_buf, some_buf_size);
      
      





dl ::共有


テンプレートクラスdl :: shared <T>は、次の問題を解決します。
  1. コンストラクターに渡された引数を持つクラスTのオブジェクトの動的作成。
  2. 参照カウンターを追加して共有所有権を提供する(boost(std):: shared_ptrなど);
  3. DL_INTERFACEマクロによって生成されたクラスオブジェクトへの暗黙的なキャスト。
クラスTのメンバー関数へのアクセスは、「->」を介して行われます。

dl ::共有クラスは、DLLの境界を越えて渡すことはできません

クラスmy_processor例::プロセッサインターフェイスがあるとします:

 class my_processor { public: my_processor( char const* name = "default name" ); int threads_count(); void process(char const* buf, std::size_t size); private: //   }; DL_NS_BLOCK(( example ) ( DL_INTERFACE( processor ) ( ( int, threads_count, () ) ( void, process, (char const*,buf)(std::size_t,size) ) ) ))
      
      





dl :: sharedの使用例を以下に示します。

 dl::shared<my_processor> p1( "some processor name" ); //   my_processor   dl::shared<my_processor> p2; //   my_processor   c    dl::shared<my_processor> p3( p1 ); // p3  p1       ,   = 2 dl::shared<my_processor> p4( dl::null_ptr ); // p4      p3.swap( p4 ); // p4    ,   p1, p3 —      p4 = dl::null_ptr; // p4      p2 = p1; // p2    p1 p2 = p1.clone(); //    my_processor //   my_processor      p2->threads_count(); p2->process( /*args*/ ); //   my_processor example::processor pi = p2; //   my_processor   example::processor // pi     ,      ,   . pi->threads_count(); pi->process(/*args*/); //   my_processor   pi.
      
      





dl :: ref


同じメソッドのセットを使用して、 DL_INTERFACEを介して宣言されたインターフェイスクラスのオブジェクトに任意のオブジェクトをキャストできるライブラリ関数。 通常、この動作は、インターフェイスクラスを引数として受け取る関数がある場合に必要であり、スタックに配置されるオブジェクトを渡す必要があります。

dl :: ref関数は注意して使用する必要があります。この場合、インターフェースクラスのオブジェクトは転送されたオブジェクトを所有せず、ユーザーはインターフェースクラスを通じてオブジェクトの寿命とその使用を制御します。 dl :: refを介して渡されたオブジェクトを参照するインターフェースクラスのオブジェクトをコピーすることは許可されており、非常に正確です(参照カウンターがないため、変更するものはありません-インターフェースクラスのオブジェクトはここで正しく動作する方法を知っています)。

 class my_processor { public: my_processor( char const* name = "default name" ); int threads_count(); void process( char const* buf, std::size_t size ); private: //   }; DL_NS_BLOCK(( example ) ( DL_INTERFACE( processor ) ( ( int, threads_count, () ) ( void, process, (char const*,buf)(std::size_t,size) ) ) )) void some_dll_func( example::processor p ) { //  p } int main() { my_processor processor( "abc" ); some_dll_func( dl::ref(processor) ); //       ,   dl::object<my_processor> return 0; }
      
      





サポートされているコンパイラ



DynLibライブラリ 、次のコンパイラ(開発環境) 完全に互換性があります。 以下のコンパイラーと部分的に互換性があります(開発環境): ここに図書館を持って



All Articles