Экспорт DLL C ++ Class, вопрос о .def файле - PullRequest
2 голосов
/ 09 октября 2008

Я хочу использовать неявные ссылки в моем проекте, и nmake действительно хочет файл .def. Проблема в том, что это класс, и я не знаю, что написать в разделе экспорта. Может ли кто-нибудь указать мне правильное направление?

Сообщение об ошибке следующее:

NMAKE: U1073: не знаю, как сделать 'DLLCLASS.def'

P.S .: Я пытаюсь собрать с помощью Windows CE Platform Builder.

Ответы [ 4 ]

8 голосов
/ 09 октября 2008

Если я правильно помню, вы можете использовать __declspec(dllexport) в классе , и VC ++ автоматически создаст экспорт для всех символов, связанных с классом (конструкторы / деструктор, методы, vtable, typeinfo и т. Д. ).

Microsoft имеет больше информации об этом здесь .

4 голосов
/ 23 марта 2010

Я нашел лучший маршрут для абстрактной фабрики.

Начните с определения чисто виртуального базового класса. Это класс без реализации, класс чисто виртуального интерфейса.

Вы можете экспортировать этот виртуальный базовый класс "абстрактный интерфейс", но для этого нет реальной причины. Когда вызывающий абонент использует его, он будет использовать его через указатель (PImpl или Указатель на реализацию), поэтому все, что знает вызывающий, - это простой адрес памяти. Файл Def, хотя и требует немного больше работы, обеспечивает преимущества, превосходящие возможности __declspec (dllexport). Какие преимущества вы спросите? Мы доберемся до этого, ты просто подожди.

Сделайте так, чтобы ваш реальный класс публично наследовал от виртуальной базы. Теперь создайте фабричный метод для создания вашего объекта и « release » вызываемый деструктор для выполнения очистки. Назовите эти методы как « ConstructMyClass » и « ReleaseMyClass ». Пожалуйста, замените « MyClass »: -)

Эти методы фабрики / выпуска должны принимать только типы POD, если им нужны какие-либо параметры (plain-old-data: integer, char и т. Д.). Тип возвращаемого значения должен быть вашим базовым классом виртуального абстрактного интерфейса или, скорее, указателем на него.

IMyClass * CreateAnObjectOfTypeIMyClass ();

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

Если вы достаточно прихотливы, вы можете обойти необходимость в методе ручная разблокировка (извините, пришлось это сделать). Как? Управляйте своими собственными ресурсами в классе с помощью умных указателей и архитектуры типа pImpl, поэтому, когда объект умирает, он очищается после себя. Это означает, что ваш класс, по бессмертным словам нашего святого и спасителя Скотта Мейерса, " прост в использовании правильно и трудно использовать неправильно " , позволяя вызывающей стороне игнорировать необходимость убирать Пусть те из нас, кто никогда не забывал назвать « .close », бросят первый камень.

Может быть, эта архитектура звучит знакомо? Должно быть, это в основном микромашинная версия COM. Ну, вроде как, по крайней мере, концепция интерфейса, заводского строительства и выпуска.

В итоге вы экспортировали интерфейс для своего класса, сделали (и экспортировали) Создайте и Уничтожьте методы, и теперь вызывающие абоненты могут вызывать ваши PleaseConstructMyClass фабричная функция, позволяющая вашей DLL возвращать полностью сконструированный, полностью реализованный и полностью запеченный объект под видом его интерфейса. Они могут вызывать все общедоступные методы вашего класса (по крайней мере, те, которые есть в вашем абстрактном виртуальном интерфейсе) и делать все самое интересное.

Когда они заканчивают работу с объектом, который был возвращен фабричной функцией, они могут вызвать функцию " ReleaseMyClass ", чтобы попросить вашу DLL очистить ресурсы объекта, или вы можете помочь им в этом. заставляя ваш класс очистить себя, делая метод " ReleaseMyClass " избыточным и бесполезным.

Если кого-то интересуют конкретные выгоды и компромиссы за использование файла Def и интерфейса (кроме моего слепого высказывания), пожалуйста, пишите, и мы можем копать глубже.

Разве тебе не нравится этот материал?

4 голосов
/ 09 октября 2008

Вы всегда можете найти оформленное имя для функции-члена, используя dumpbin / символы myclass.obj

в моем случае

class A {
   public:
     A( int ){}
};

на свалке dumpbin был указан символ ??0A@@QAE@H@Z (public: __thiscall A::A(int))

Помещение этого символа в файл .def заставляет компоновщик создать символ A :: A (int) в символах экспорта.

НО! , как @paercebal заявляет в своем комментарии: ручной ввод декорированных (искаженных) имен является трудоемкой и, к сожалению, не гарантируемой переносимостью для версий компилятора. *

0 голосов
/ 09 октября 2008

Решение заключается в следующем:

  • , поскольку класс экспортируется, вам также необходимо добавить экспортированные методы в файл .def

  • Я не узнал, как экспортировать конструктор, поэтому я использовал фабричный метод (статический), который будет возвращать новые экземпляры объекта

  • другие функции будут экспортированы путем добавления обычного объявления об экспорте в файл .def

Надеюсь, кто-то получит пользу от этой информации.

...