Карта сайта Kansoftware
НОВОСТИУСЛУГИРЕШЕНИЯКОНТАКТЫ
Разработка программного обеспечения

Tutorial

Boost , The Boost C++ Libraries BoostBook Documentation Subset , Chapter 11. Boost.DLL

Boost C++ Libraries

...one of the most highly regarded and expertly designed C++ library projects in the world. Herb Sutter and Andrei Alexandrescu, C++ Coding Standards

PrevUpHomeNext

Этот учебник предоставляется, чтобы дать вам представление о том, как создавать и использовать плагины.

Первое, что нужно сделать при создании собственных плагинов, это определить интерфейс плагина. Существует пример абстрактного класса, который будет нашим API плагина:

#include <string>
class my_plugin_api {
public:
   virtual std::string name() const = 0;
   virtual float calculate(float x, float y) = 0;
   virtual ~my_plugin_api() {}
};

Теперь давайте создадим библиотеку DLL/DSO, которая будет поддерживать реализацию интерфейса плагина и экспортировать его с помощью<extern "C">и<BOOST_SYMBOL_EXPORT>:

#include <boost/config.hpp> // for BOOST_SYMBOL_EXPORT
#include "../tutorial_common/my_plugin_api.hpp"
namespace my_namespace {
class my_plugin_sum : public my_plugin_api {
public:
    my_plugin_sum() {
        std::cout << "Constructing my_plugin_sum" << std::endl;
    }
    std::string name() const {
        return "sum";
    }
    float calculate(float x, float y) {
        return x + y;
    }
    ~my_plugin_sum() {
        std::cout << "Destructing my_plugin_sum ;o)" << std::endl;
    }
};
// Exporting `my_namespace::plugin` variable with alias name `plugin`
// (Has the same effect as `BOOST_DLL_ALIAS(my_namespace::plugin, plugin)`)
extern "C" BOOST_SYMBOL_EXPORT my_plugin_sum plugin;
my_plugin_sum plugin;
} // namespace my_namespace

Простое приложение, которое загружает плагин с помощью<boost::dll::import>и<append_decorations>:

#include <boost/dll/import.hpp> // for import_alias
#include <iostream>
#include "../tutorial_common/my_plugin_api.hpp"
namespace dll = boost::dll;
int main(int argc, char* argv[]) {
    boost::filesystem::path lib_path(argv[1]);          // argv[1] contains path to directory with our plugin library
    boost::shared_ptr<my_plugin_api> plugin;            // variable to hold a pointer to plugin variable
    std::cout << "Loading the plugin" << std::endl;
    plugin = dll::import<my_plugin_api>(          // type of imported symbol is located between `<` and `>`
        lib_path / "my_plugin_sum",                     // path to the library and library name
        "plugin",                                       // name of the symbol to import
        dll::load_mode::append_decorations              // makes `libmy_plugin_sum.so` or `my_plugin_sum.dll` from `my_plugin_sum`
    );
    std::cout << "plugin->calculate(1.5, 1.5) call:  " << plugin->calculate(1.5, 1.5) << std::endl;
}

Это приложение выведет:

Loading the plugin
Constructing my_plugin_sum
plugin->calculate(1.5, 1.5) call:  3
Destructing my_plugin_sum ;o)

Full sources:

Back to the Top

В предыдущем примере мы импортировали из плагина одну переменную. Давайте сделаем класс, который использует наш плагин API плагин и имеет некоторое состояние:

#include <boost/dll/alias.hpp> // for BOOST_DLL_ALIAS   
#include "../tutorial_common/my_plugin_api.hpp"
namespace my_namespace {
class my_plugin_aggregator : public my_plugin_api {
    float aggr_;
    my_plugin_aggregator() : aggr_(0) {}
public:
    std::string name() const {
        return "aggregator";
    }
    float calculate(float x, float y) {
        aggr_ += x + y;
        return aggr_;
    }
    // Factory method
    static boost::shared_ptr<my_plugin_aggregator> create() {
        return boost::shared_ptr<my_plugin_aggregator>(
            new my_plugin_aggregator()
        );
    }
};
BOOST_DLL_ALIAS(
    my_namespace::my_plugin_aggregator::create, // <-- this function is exported with...
    create_plugin                               // <-- ...this alias name
)
} // namespace my_namespace

Как вы можете видеть,<my_namespace::create_plugin>является фабричным методом, который создает экземпляры<my_namespace::my_plugin_aggregator>. Мы экспортируем этот метод с именем «create_plugin» с использованием<BOOST_DLL_ALIAS>.

#include <boost/dll/import.hpp> // for import_alias
#include <boost/function.hpp>
#include <iostream>
#include "../tutorial_common/my_plugin_api.hpp"
namespace dll = boost::dll;
int main(int argc, char* argv[]) {
    boost::filesystem::path shared_library_path(argv[1]);               // argv[1] contains path to directory with our plugin library
    shared_library_path /= "my_plugin_aggregator";
    typedef boost::shared_ptr<my_plugin_api> (pluginapi_create_t)();
    boost::function<pluginapi_create_t> creator;
    creator = boost::dll::import_alias<pluginapi_create_t>(             // type of imported symbol must be explicitly specified
        shared_library_path,                                            // path to library
        "create_plugin",                                                // symbol to import
        dll::load_mode::append_decorations                              // do append extensions and prefixes
    );
    boost::shared_ptr<my_plugin_api> plugin = creator();
    std::cout << "plugin->calculate(1.5, 1.5) call:  " << plugin->calculate(1.5, 1.5) << std::endl;
    std::cout << "plugin->calculate(1.5, 1.5) second call:  " << plugin->calculate(1.5, 1.5) << std::endl;
    std::cout << "Plugin Name:  " << plugin->name() << std::endl;
}

В этом приложении мы импортировали заводской метод с использованием<boost::dll::import_alias>.

[Caution]Caution

Будьте осторожны:<creator>переменная содержит ссылку на загруженную общую библиотеку. Если эта переменная выходит за рамки или будет сброшена, тоDLL/DSO будет выгружен, и любая попытка отклонить переменную<plugin>приведет кнеопределенному поведению.

Результатом применения будет следующее:

plugin->calculate(1.5, 1.5) call:  3
plugin->calculate(1.5, 1.5) second call:  6
Plugin Name:  aggregator

Full sources:

Back to the Top

Рассмотрим ситуацию: у нас есть несколько плагинов, но только некоторые из них имеют нужные нам символы. Напишем функцию, которая ищет список плагинов и пытается найти<"create_plugin">метод.

#include <boost/dll/import.hpp> // for import_alias
#include <boost/make_shared.hpp>
#include <boost/function.hpp>
#include <iostream>
#include "../tutorial_common/my_plugin_api.hpp"
namespace dll = boost::dll;
std::size_t search_for_symbols(const std::vector<boost::filesystem::path>& plugins) {
    std::size_t plugins_found = 0;
    for (std::size_t i = 0; i < plugins.size(); ++i) {
        std::cout << "Loading plugin: " << plugins[i] << '\n';
        dll::shared_library lib(plugins[i], dll::load_mode::append_decorations);
        if (!lib.has("create_plugin")) {
            // no such symbol
            continue;
        }
        // library has symbol, importing...
        typedef boost::shared_ptr<my_plugin_api> (pluginapi_create_t)();
        boost::function<pluginapi_create_t> creator
            = dll::import_alias<pluginapi_create_t>(boost::move(lib), "create_plugin");
        std::cout << "Matching plugin name: " << creator()->name() << std::endl;
        ++ plugins_found;
    }
    return plugins_found;
}

Если мы назовем этот метод для всех наших плагинов, мы получим следующий результат:

Loading plugin: "/test/libmy_plugin_aggregator.so"
Matching plugin name: aggregator
Loading plugin: "/test/libmy_plugin_sum.so"
Constructing my_plugin_sum
Destructing my_plugin_sum ;o)

Full sources:

Back to the Top

Подключение плагина к исполняемому имеет преимущества

  • уменьшение общего размера распределения
  • Упрощение установки распределения
  • Более быстрая загрузка плагинов

Давайте начнем с создания подключаемого плагина. Такой плагин будет иметь заголовок, общий для самой библиотеки плагинов и для исполняемого файла:

#include <boost/dll/alias.hpp>                          // for BOOST_DLL_ALIAS
#include <boost/shared_ptr.hpp>
#include "../tutorial_common/my_plugin_api.hpp"
namespace my_namespace {
    boost::shared_ptr<my_plugin_api> create_plugin();   // Forward declaration
} // namespace my_namespace
BOOST_DLL_ALIAS(
    my_namespace::create_plugin,                        // <-- this function is exported with...
    create_plugin                                       // <-- ...this alias name
)

Главный трюк здесь - определение псевдонима. При подключении плагина к исполняемому файлу псевдонимдолжен быть инстанцированв одном из исходных файлов исполняемого файла. В противном случае линкер оптимизирует наш плагин.

Вот как выглядит реализация плагина:

#include "static_plugin.hpp" // this is essential, BOOST_SYMBOL_ALIAS must be seen in this file
#include <boost/make_shared.hpp>
#include <iostream>
namespace my_namespace {
class my_plugin_static : public my_plugin_api {
public:
    my_plugin_static() {
        std::cout << "Constructing my_plugin_static" << std::endl;
    }
    std::string name() const {
        return "static";
    }
    float calculate(float x, float y) {
        return x - y;
    }
    ~my_plugin_static() {
        std::cout << "Destructing my_plugin_static" << std::endl;
    }
};
boost::shared_ptr<my_plugin_api> create_plugin() {
    return boost::make_shared<my_plugin_static>();
}
} // namespace my_namespace

Теперь, если мы сделаем статическую библиотеку из исходного файла и свяжем эту статическую библиотеку со следующим кодом, мы сможем импортировать символы из плагина:

#include <boost/dll/shared_library.hpp>         // for shared_library
#include <boost/dll/runtime_symbol_info.hpp>    // for program_location()
#include "static_plugin.hpp"                    // without this headers some compilers may optimize out the `create_plugin` symbol
#include <boost/function.hpp>
#include <iostream>
namespace dll = boost::dll;
int main() {
    dll::shared_library self(dll::program_location());
    std::cout << "Call function" << std::endl;
    boost::function<boost::shared_ptr<my_plugin_api>()> creator
        = self.get_alias<boost::shared_ptr<my_plugin_api>()>("create_plugin");
    std::cout << "Computed Value: " << creator()->calculate(2, 2) << std::endl;
}

[Note]Note

Флаг «-rdynamic» должен использоваться при подключении плагина к исполняемому файлу на ОС Linux. В противном случае загрузка символов из себявыйдет из строя.

Запуск программы выведет следующее:

Call function
Constructing my_plugin_static
Computed Value: 0
Destructing my_plugin_static
[Note]Note

Если мы хотим создать традиционный плагин, который находится в отдельной общей библиотеке, все, что нам нужно сделать, это удалить строку<#include "static_plugin.hpp">и заменить<dll::program_location()>местоположением и именем плагина.

Full sources:

Back to the Top

Давайте создадим исполняемый файл, подключим к нему плагин и попытаемся загрузить все существующие плагины:

namespace dll = boost::dll;
class plugins_collector {
    // Name => plugin
    typedef boost::container::map<std::string, dll::shared_library> plugins_t;
    boost::filesystem::path         plugins_directory_;
    plugins_t                       plugins_;
    // loads all plugins in plugins_directory_
    void load_all();
    // Gets `my_plugin_api` instance using "create_plugin" or "plugin" imports,
    // stores plugin with its name in the `plugins_` map.
    void insert_plugin(BOOST_RV_REF(dll::shared_library) lib);
public:
    plugins_collector(const boost::filesystem::path& plugins_directory)
        : plugins_directory_(plugins_directory)
    {
        load_all();
    }
    void print_plugins() const;
    std::size_t count() const;
    // ...   
};

int main(int argc, char* argv[]) {
    plugins_collector plugins(argv[1]);
    std::cout << "\n\nUnique plugins " << plugins.count() << ":\n";
    plugins.print_plugins();
    // ...

С флагами по умолчанию вы получите очень странный выход:

Loaded (0x180db60):"/libs/dll/test/libmy_plugin_aggregator.so"
Constructing my_plugin_static
Destructing my_plugin_static
...
Unique plugins 2:
(0x180db60): static
(0x180e3b0): sum
Destructing my_plugin_sum ;o)

Почему<my_plugin_static>был построен, когда мы загружали<my_plugin_aggregator>?

Это связано с тем, что функция<create_plugin>от<libmy_plugin_aggregator.so>была скрыта функцией<create_plugin>от другого плагина. Динамический линкер считал, что<create_plugin>уже загружен и нет необходимости загружать его снова.

[Warning]Warning

Используйте флаг «-fvisibility=hidden» (по крайней мере, для плагинов) при компиляции для платформ POSIX. Этот флаг делает ваш код более портативным («-fvisibility=hidden» — поведение по умолчанию под Windows), уменьшает размер двоичных файлов и улучшает время загрузки двоичных файлов.

Теперь, если мы перекомпилируем ваш пример с «-fvisibility=hidden», мы получим следующий вывод:

Loaded (0x2406b60):"/libs/dll/test/libmy_plugin_aggregator.so"
Loaded (0x2407410):"/libs/dll/test/libgetting_started_library.so"
Constructing my_plugin_sum
...
Unique plugins 3:
(0x2406b60): aggregator
(0x7fd1cadce2c8): static
(0x24073b0): sum
Destructing my_plugin_sum ;o)

Full sources:

Back to the Top

Повышаю. DLL не предоставляет механизм извлечения библиотечных разгрузок. Однако такая задача может быть легко выполнена.

Все, что вам нужно сделать, это написать простой класс, который хранит обратные вызовы и вызывает их при разрушении:

#include <boost/dll/alias.hpp> // for BOOST_DLL_ALIAS
#include <boost/function.hpp>
#include <vector>
namespace my_namespace {
struct on_unload {
    typedef boost::function<void()> callback_t;
    typedef on_unload this_type;
    ~on_unload() {
        for (std::size_t i = 0; i < callbacks_.size(); ++i) {
            callback_t& function = callbacks_[i];
            function(); // calling the callback
        }
    }
    // not thread safe
    static void add(const callback_t& function) {
        static this_type instance;
        instance.callbacks_.push_back(function);
    }
private:
    std::vector<callback_t> callbacks_;
    on_unload() {} // prohibit construction outside of the `add` function
};
// Exporting the static "add" function with name "on_unload"
BOOST_DLL_ALIAS(my_namespace::on_unload::add, on_unload)
} // namespace my_namespace

В приведенном выше примере<my_namespace::on_unload>представлена однотонная структура, удерживающая вектор обратных вызовов и вызывающая все обратные вызовы при разрушении.

Теперь мы можем загрузить эту библиотеку и предоставить обратный звонок:

#include <boost/dll/import.hpp>
#include <boost/function.hpp>
#include <iostream>
typedef boost::function<void()> callback_t;
void print_unloaded() {
    std::cout << "unloaded" << std::endl;
}
int main(int argc, char* argv[]) {
    // argv[1] contains full path to our plugin library
    boost::filesystem::path shared_library_path =  argv[1];
    // loading library and getting a function from it
    boost::function<void(const callback_t&)> on_unload
        = boost::dll::import_alias<void(const callback_t&)>(
            shared_library_path, "on_unload"
        );
    on_unload(&print_unloaded); // adding a callback
    std::cout << "Before library unload." << std::endl;
    // Releasing last reference to the library, so that it gets unloaded
    on_unload.clear();
    std::cout << "After library unload." << std::endl;
}

Если мы запустим пример, мы получим следующий вывод:

Before library unload.
unloaded
After library unload.

Full sources:

Back to the Top

Может возникнуть ситуация, когда мы не знаем названия функций в плагине. В этом случае библиотека может быть полезной.

Представьте себе ситуацию: у нас есть проект «Анна», который способен загружать и использовать плагины, содержащие функции с подписью<void(const std::string&)>. Мы не знаем названий функций, но хотим их как-то узнать.

Решение было бы довольно простым. Давайте согласимся с разработчиками плагинов, что они могут называть функции так, как им нравится, но все псевдонимы функций плагина должны быть расположены в разделе «Анна»:

#include <boost/dll/alias.hpp> // for BOOST_DLL_ALIAS_SECTIONED
#include <iostream>
#include <string>
void print(const std::string& s) {
    std::cout << "Hello, " << s << '!' << std::endl;
}
BOOST_DLL_ALIAS_SECTIONED(print, print_hello, Anna)

#include <boost/dll/alias.hpp> // for BOOST_DLL_ALIAS_SECTIONED
#include <string>
#include <iostream>
void print_howdy(const std::string& s) {
    std::cout << "How're you doing, " << s << '?' << std::endl;
}
void print_bored(const std::string& s) {
    std::cout << "Are you bored, " << s << '?' << std::endl;
}
BOOST_DLL_ALIAS_SECTIONED(print_howdy, howdy, Anna)
BOOST_DLL_ALIAS_SECTIONED(print_bored, are_you_bored, Anna)

Теперь мы можем легко получить эти функции с помощью<boost::dll::library_info>:

#include <boost/dll/shared_library.hpp>
#include <boost/dll/library_info.hpp>
#include <iostream>
void load_and_execute(const boost::filesystem::path libraries[], std::size_t libs_count) {
    const std::string username = "User";
    for (std::size_t i = 0; i < libs_count; ++i) {
        // Class `library_info` can extract information from a library
        boost::dll::library_info inf(libraries[i]);
        // Getting symbols exported from 'Anna' section
        std::vector<std::string> exports = inf.symbols("Anna");
        // Loading library and importing symbols from it
        boost::dll::shared_library lib(libraries[i]);
        for (std::size_t j = 0; j < exports.size(); ++j) {
            std::cout << "\nFunction '" << exports[j] << "' prints:\n\t";
            lib.get_alias<void(const std::string&)>(exports[j]) // importing function
                (username);                                     // calling function
        }
    }
}

Если мы запустим пример, мы получим следующий вывод:

Function 'print_hello' prints:
	Hello, User!
Function 'are_you_bored' prints:
	Are you bored, User?
Function 'howdy' prints:
	How're you doing, User?
[Note]Note

<BOOST_DLL_ALIAS>Макро по умолчанию помещает все псевдонимы в раздел «boostdll».

Full sources:

Back to the Top

Как отмечается в документации к<boost::dll::import>переменным и функциям, возвращаемым из этих функций, содержится ссылка на общую библиотеку. Однако вложенные объекты и объекты, возвращаемые<import*>функциями, не содержат ссылки на общую библиотеку. Нет никакого способа решить эту проблему на подъеме. Уровень библиотеки DLL, но вы можете решить эту проблему самостоятельно. Вот пример того, как это можно сделать.

В этом примере мы будем импортировать функцию, которая создает экземпляр плагина и связывает этот экземпляр с shared_library.

Прежде всего, необходимо определить новый плагин api:

#include "../tutorial_common/my_plugin_api.hpp"
#include <boost/filesystem/path.hpp>
class my_refcounting_api: public my_plugin_api {
public:
    // Returns path to shared object that holds a plugin.
    // Must be instantiated in plugin.
    virtual boost::filesystem::path location() const = 0;
};

Этот API не сильно отличается от предыдущего. Добавлен только один абстрактный метод.

Теперь давайте определим плагин:

#include "refcounting_plugin.hpp"
#include <boost/dll/runtime_symbol_info.hpp> // for this_line_location()
namespace my_namespace {
class my_plugin_refcounting : public my_refcounting_api {
public:
    // Must be instantiated in plugin
    boost::filesystem::path location() const {
        return boost::dll::this_line_location(); // location of this plugin
    }
    std::string name() const {
        return "refcounting";
    }
    // ...
};
} // namespace my_namespace
// Factory method. Returns *simple pointer*!
my_refcounting_api* create() {
    return new my_namespace::my_plugin_refcounting();
}

Этот плагин не сильно отличается от наших предыдущих примеров, за исключением дополнительного метода, который вызывает<boost::dll::this_line_location>и<create()>функцию, которая возвращает простой указатель вместо<boost::shared_ptr>.

Теперь давайте создадим функцию, которая связывает вновь созданный экземпляр<my_refcounting_api>с общей библиотекой:

#include <boost/shared_ptr.hpp>
#include <boost/make_shared.hpp>
#include <boost/dll/shared_library.hpp>
struct library_holding_deleter {
    boost::shared_ptr<boost::dll::shared_library> lib_;
    void operator()(my_refcounting_api* p) const {
        delete p;
    }
};
inline boost::shared_ptr<my_refcounting_api> bind(my_refcounting_api* plugin) {
    // getting location of the shared library that holds the plugin
    boost::filesystem::path location = plugin->location();
    // `make_shared` is an efficient way to create a shared pointer
    boost::shared_ptr<boost::dll::shared_library> lib
        = boost::make_shared<boost::dll::shared_library>(location);
    library_holding_deleter deleter;
    deleter.lib_ = lib;
    return boost::shared_ptr<my_refcounting_api>(
        plugin, deleter
    );
}

В<bind>методе мы называем<plugin->location()>. Этот вызов приводит к вызову<boost::dll::this_line_location>и возвращает местоположение плагина. Тогда<shared_ptr>, который держит<shared_library>, создается с помощью<make_shared>призыва.

После этого мы создаем<boost::shared_ptr<my_refcounting_api>>с<library_holding_deleter>, который хранит экземпляр общей библиотеки.

[Note]Note

Используйте<std::unique_ptr<my_refcounting_api>>вместо<my_refcounting_api*>в производственном коде, чтобы избежать утечек памяти, когда<plugin->location()>бросает или когда какой-либо другой класс поднимает исключение.

Вот и все, теперь мы можем получить пример плагина:

#include <boost/dll/import.hpp>
#include <boost/function.hpp>
inline boost::shared_ptr<my_refcounting_api> get_plugin(
    boost::filesystem::path path, const char* func_name)
{
    typedef my_refcounting_api*(func_t)();
    boost::function<func_t> creator = boost::dll::import_alias<func_t>(
        path,
        func_name,
        boost::dll::load_mode::append_decorations   // will be ignored for executable
    );
    // `plugin` does not hold a reference to shared library. If `creator` will go out of scope, 
    // then `plugin` can not be used.
    my_refcounting_api* plugin = creator();
    // Returned variable holds a reference to 
    // shared_library and it is safe to use it.
    return bind( plugin );
    // `creator` goes out of scope here and will be destroyed.
}

Вот как выглядит функция<main()>:

Загрузка плагина Runtime

Плагин был связан в

Код

#include <iostream>
#include "refcounting_api.hpp"
int main(int argc, char* argv[]) {
    boost::shared_ptr<my_refcounting_api> plugin = get_plugin(
        boost::filesystem::path(argv[1]) / "refcounting_plugin",
        "create_refc_plugin"
    );
    std::cout << "Plugin name: " << plugin->name()
              << ", \nlocation: " << plugin->location()
              << std::endl;
}

#include <boost/dll/runtime_symbol_info.hpp> // program_location()
#include <iostream>
#include "refcounting_plugin.hpp"
int main() {
    boost::shared_ptr<my_refcounting_api> plugin = get_plugin(
        boost::dll::program_location(),
        "create_refc_plugin"
    );
    std::cout << "Plugin name: " << plugin->name()
              << ", \nlocation: " << plugin->location()
              << std::endl;
}

Выход

Plugin name: refcounting,
location: "/libs/dll/librefcounting_plugin.so"
Plugin name: refcounting,
location: "/tutorial8_static"

Full sources:

Back to the Top

Это тривиальный пример, но он имеет одно сложное место. Когда вы импортируете функцию C, это имя, вы должны использовать<boost::dll::import>, а не<boost::dll::import_alias>:

#include <boost/dll/import.hpp>         // for dll::import
#include <boost/dll/shared_library.hpp> // for dll::shared_library
#include <boost/function.hpp>
#include <iostream>
#include <windows.h>
namespace dll = boost::dll;
int main() {
    typedef HANDLE(__stdcall GetStdHandle_t)(DWORD );       // function signature with calling convention
    // OPTION #0, requires C++11 compatible compiler that understands GetStdHandle_t signature.
    auto get_std_handle = dll::import<GetStdHandle_t>(
        "Kernel32.dll",
        "GetStdHandle",
        boost::dll::load_mode::search_system_folders
    );
    std::cout << "0.0 GetStdHandle() returned " << get_std_handle(STD_OUTPUT_HANDLE) << std::endl;
    // You may put the `get_std_handle` into boost::function<>. But boost::function<Signature> can not compile with
    // Signature template parameter that contains calling conventions, so you'll have to remove the calling convention.
    boost::function<HANDLE(DWORD)> get_std_handle2 = get_std_handle;
    std::cout << "0.1 GetStdHandle() returned " << get_std_handle2(STD_OUTPUT_HANDLE) << std::endl;
    // OPTION #1, does not require C++11. But without C++11 dll::import<> can not handle calling conventions,
    // so you'll need to hand write the import.
    dll::shared_library lib("Kernel32.dll", dll::load_mode::search_system_folders);
    GetStdHandle_t& func = lib.get<GetStdHandle_t>("GetStdHandle");
    // Here `func` does not keep a reference to `lib`, you'll have to deal with that on your own.
    std::cout << "1.0 GetStdHandle() returned " << func(STD_OUTPUT_HANDLE) << std::endl;
    return 0;
}

Full sources:

Back to the Top


PrevUpHomeNext

Статья Tutorial раздела The Boost C++ Libraries BoostBook Documentation Subset Chapter 11. Boost.DLL может быть полезна для разработчиков на c++ и boost.




Материалы статей собраны из открытых источников, владелец сайта не претендует на авторство. Там где авторство установить не удалось, материал подаётся без имени автора. В случае если Вы считаете, что Ваши права нарушены, пожалуйста, свяжитесь с владельцем сайта.



:: Главная :: Chapter 11. Boost.DLL ::


реклама


©KANSoftWare (разработка программного обеспечения, создание программ, создание интерактивных сайтов), 2007
Top.Mail.Ru

Время компиляции файла: 2024-08-30 11:47:00
2025-05-19 17:37:14/0.015216827392578/1