//========== 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), () ) ) ))
The preprocessor will generate a test :: lib class that performs dynamic DLL loading and contains the listed functions sum , mul, and epsilon . To connect the DLL to the application, you must include the provided header file test_lib.hpp in the source code. Next, create an object of the class test :: lib . Access to the exported DLL functions is possible via '.' or '->'. //========== 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; }
//========== 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 )
//========== 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; }
//========== 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 )
//========== 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'
//========== 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; }
#include <dl/include.hpp>
DL_BLOCK ( // declarations )
DL_NS_BLOCK( (ns0, ns1, ns2 … )/* , 10*/ ( // declarations ))
DL_C_LIBRARY(lib_class) ( /*functions*/ ( ret_type, call, (name, import_name), arguments ) )
DL_BLOCK ( DL_C_LIBRARY( my_lib ) ( ( void, __stdcall, (func), (int)(int,s)(double,V,=1.0) ) ( int, __stdcall, (fn, "fn@0"), (int,a) ) ( int, __stdcall, (fn), () ) ) )
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; }
- automatic interception of C ++ exceptions on the DLL side; - returning the value across the DLL boundaries, signaling the presence of an exception; - the generation of a new exception in case the exception on the DLL side was intercepted (with the recovery of the description and information about the type of exception).
DL_LIBRARY( name ) ( /*functions*/ ( ret_type, name, arguments ) )
//========== 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, () ) ) ))
//========== 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; }
//========== 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 )
- automatic interception of C ++ exceptions on the DLL side; - returning the value across the DLL boundaries, signaling the presence of an exception; - the generation of a new exception in case the exception on the DLL side was intercepted (with the recovery of the description and information about the type of exception).The wrapper class generated by this macro has a shared ownership of the object that implements this interface. Shared ownership is provided by a reference counting mechanism, i.e. when a wrapper class object is copied, an internal function is called to increase the reference count, and when destroyed, an internal function to reduce the reference count. When the counter reaches 0, the object is automatically deleted. Access to interface methods is done via '.' or '->'.
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);
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<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.
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; }
Source: https://habr.com/ru/post/137969/
All Articles