Вопрос

Я читал много руководств/статей о неуправляемых DLL на C++.Однако, хоть убей, я, похоже, не могу понять эту концепцию.Меня легко сбивает с толку кажущееся разногласие по поводу того, нужен ли заголовочный файл, как его экспортировать, нужен ли мне файл .lib и что у вас есть.

Итак, предположим, что у меня есть такая функция:

public int calculateSquare(int num)
{
    return num*num;
}

Не обращая внимания на реальный код, что мне нужно, чтобы превратить эту простую функцию в DLL, которую я затем смогу вызвать?Мне просто добавить __dllexport или что-то еще в первую строку или мне нужен заголовок?Я озадачен всем этим.

Это было полезно?

Решение

Я не могу подчеркнуть это достаточно, компилятор C ++ не видит заголовочные файлы, после того, как препроцессор сделан, есть только один большой исходный файл (также называемый модулем компиляции). Так что строго вам не нужен заголовок для экспорта этой функции из DLL. Что вам нужно, так это какая-то форма условной компиляции, чтобы экспортировать функцию в dll, которую вы компилируете, и импортировать ее в код клиента.

Обычно это делается с помощью комбинации макросов и заголовочных файлов. Вы создаете макрос с именем MYIMPORTEXPORT и с помощью условных операторов макросов заставляете его работать как __declspec (dllexport) в dll и __declspec (dllimport) в клиентском коде.

в файле MYIMPORTEXPORT.h

#ifdef SOME_CONDITION
#define MYIMPORTEXPORT __declspec( dllexport )
#else
#define MYIMPORTEXPORT __declspec( dllimport )
#endif

в файле MyHeader.h

#include <MyImportExport.h>

MYIMPORTEXPORT public int calculateSquare(int num)
{
    return num*num;
}

в файле dll .cpp

#define SOME_CONDITION

#include <MyHeader.h>

в клиентском коде .cpp файл

#include <MyHeader.h>

Конечно, вам также нужно сообщить компоновщику, что вы создаете dll, с помощью / параметр DLL .

Процесс сборки также создает файл .lib, это статическая библиотека, в данном случае называемая заглушкой, на которую клиентский код должен ссылаться, как если бы он ссылался на настоящую статическую библиотеку. Автоматически, DLL будет загружен при запуске клиентского кода. Конечно, dll должна быть найдена ОС через механизм поиска, что означает, что вы не можете поместить dll просто где-нибудь, но в определенном месте. Здесь подробнее об этом.

Очень удобный инструмент для просмотра того, экспортировали ли вы правильную функцию из dll и правильно ли импортирует код клиента, - это свалка . Запустите его с / EXPORTS и / IMPORTS соответственно.

Другие советы

QBziZ 'ответ достаточно правильный. См. Неуправляемые библиотеки DLL в C ++

Для завершения: В C ++, если вам нужно использовать символ, вы должны сообщить компилятору о его существовании, а часто и его прототипе .

На других языках компилятор просто исследует библиотеку самостоятельно и найдет символ et voil & # 224; .

В C ++ вы должны сообщить компилятору.

Смотрите заголовок C / C ++ как оглавление книги

Лучший способ - поместить в какое-то общее место необходимый код. & Quot; интерфейс " ;, если хотите. Обычно это делается в заголовочном файле, который называется header, потому что обычно это не независимый исходный файл. Заголовок - это всего лишь файл, целью которого является включение (т.е. копирование / вставка препроцессором) в настоящие исходные файлы.

По сути, кажется, что вы должны объявить дважды символ (функцию, класс, что угодно). Это почти ересь по сравнению с другими языками.

Вы должны увидеть его в виде книги, со сводной таблицей или указателем. В таблице у вас есть все главы. В тексте у вас есть главы и их содержание.

А иногда вы просто счастливы, что у вас есть список глав.

В C ++ это заголовок.

Как насчет DLL?

Итак, вернемся к проблеме с DLL: цель DLL - экспортировать символы, которые будет использовать ваш код.

Таким образом, в C ++ вы должны одновременно экспортировать код при компиляции (то есть в Windows, например, использовать __declspec) и " publish " таблица того, что экспортируется (то есть имеет «публичные» заголовки, содержащие экспортированные объявления).

Контрольный список для экспорта функций:

  • Подходит ли соглашение о вызовах для вызывающего абонента?(это определяет, как передаются параметры и результаты и кто отвечает за очистку стека).Вы должны явно указать свое соглашение о вызовах.
  • Под каким именем будет экспортирован символ?В C++ обычно необходимо украшать («искажать») имена символов, напримерразличать разные перегрузки.
  • Сообщите компоновщику, чтобы он сделал функцию видимой как DLL Export.

В MSVC:

  • __stdcall (это соглашение о вызовах Паскаля) является типичным соглашением о вызовах для экспортируемых символов, которое, я думаю, поддерживается большинством клиентов.
  • extern "C" позволяет экспортировать символ в стиле C без искажения имени.
  • использовать __declspec(dllexport) чтобы отметить символ для экспорта, или свяжите отдельный файл .def, в котором перечислены символы, подлежащие экспорту.С помощью файла .def вы также можете экспортировать только по порядковому номеру (не по имени) и изменить имя экспортируемого символа.

Вам необходимо экспортировать функцию, используя __declspec (dllexport) или добавив функцию в файл определения модуля (.def). Затем скомпилируйте проект как DLL.

На стороне клиента у вас есть два варианта. Либо используйте библиотеку импорта (.lib), которая создается при компиляции DLL. Простое соединение с вашим клиентским проектом с этой библиотекой даст вам доступ к функциям, экспортированным из DLL. И вам нужен файл заголовка, потому что компилятор должен знать сигнатуру вашей функции - что он возвращает int и принимает int. Напомним, что вам нужно связать библиотеку импорта (.lib) и файл заголовка, который содержит заголовок вашей функции.

Другой способ - это динамическая загрузка DLL с помощью WinAPI , вызова LoadLibrary , а затем GetProcAddress для получения указателя на функцию. Указатель на функцию должен иметь правильный тип, чтобы компилятор мог задать ей правильные параметры и использовать правильное соглашение о вызовах.

Лицензировано под: CC-BY-SA с атрибуция
Не связан с StackOverflow
scroll top