Какие проблемы могут возникнуть при использовании скомпилированной DLL (плагина) G ++ в скомпилированном приложении VC ++? - PullRequest
4 голосов
/ 04 февраля 2012

Я использую и приложение скомпилировано с помощью Visual C ++ Compiler.Он может загружать плагины в виде .dll.Довольно неважно, что именно это делает, факт:

UML Diagram

Это включает в себя вызов функций из .dll, которые возвращают указатель на объект API приложений и т. Д.

Мой вопрос: какие проблемы могут возникнуть, когда приложение вызывает функцию из .dll, получает из нее указатель и работает с ней.Например, что-то, что приходит мне в голову, это размер указателя.Отличается ли это в VC ++ и G ++?Если да, это может привести к сбою приложения?

Я не хочу использовать IDE Visual Studio (к сожалению, это «предпочтительный» способ использования SDK для приложений).Могу ли я настроить G ++ для компиляции как VC ++ ?

PS: я использую MINGW GNU G ++

Ответы [ 6 ]

6 голосов
/ 04 февраля 2012

Пока приложение и DLL скомпилированы на одном компьютере, и если они оба используют только ABI C, все будет в порядке.

Что вы, безусловно, не можете сделать, это использовать какую-либо конструкцию C ++. Например, вы не должны new[] массив в основном приложении и позволить DLL delete[] его. Это потому, что не существует фиксированного C ++ ABI, и, следовательно, нет никакого способа, которым какой-либо данный компилятор знает, как другой компилятор реализует структуры данных C ++. Это справедливо даже для разных версий MSVC ++, которые не совместимы с ABI.

4 голосов
/ 04 февраля 2012

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

Если ваши компоненты используют только extern "C" интерфейсы для общения друг с другом, вы, вероятно, можете сделать это, хотя даже там вам нужно быть осторожным. Обе среды выполнения C ++ будут иметь код запуска и завершения работы, и нет никакой гарантии, что какой бы компоновщик, который вы используете для сборки приложения, знал, как включить этот код для другого компилятора. Вы в значительной степени должны связать g ++ - например, скомпилированный код с g ++.

Если вы используете функции C ++ только с одним компилятором и используете компоновщик этого компилятора, то это с гораздо большей вероятностью будет работать.

3 голосов
/ 04 февраля 2012

Это должно быть хорошо, если вы знаете, что делаете.Но есть некоторые вещи, на которые следует обратить внимание:

Я предполагаю, что интерфейс между EXE и DLL является интерфейсом "C" или чем-то вроде COM, где единственные классы C ++, доступные через чистые вирулентные интерфейсы.Это усложняется, если вы экспортируете конкретный класс через DLL.

  1. 32-разрядный или 64-разрядный.32-битное приложение не будет загружать 64-битную DLL и наоборот.Убедитесь, что они совпадают.

  2. Соглашение о вызовах.__cdecl против __stdcall.Часто приложения Visual Studio компилируются с флагами, которые принимают __stdcall в качестве соглашения о вызовах по умолчанию (или это явно указано в прототипе функции).Поэтому убедитесь, что компиляторы g ++ генерируют код, который соответствует типу вызова, ожидаемому EXE.В противном случае экспортируемая функция может запуститься, но стек может быть уничтожен при возврате.Если вы выполняете отладку через такой сбой, есть большая вероятность, что соглашение cdecl vs stdcall было указано неверно.Легко исправить.

  3. C-Runtime вряд ли будет разделен между EXE и DLL, поэтому не смешивайте и не сопоставляйте.Указатель, выделенный с новым или malloc в EXE, не должен быть освобожден с удалением или свободным в DLL (и наоборот).Аналогично, дескрипторы FILE, возвращаемые функцией fopen (), не могут быть разделены между EXE и DLL.Скорее всего, произойдет сбой, если что-нибудь из этого произойдет ... что приведет меня к следующему пункту ....

  4. Заголовочные файлы C ++ со встроенным кодом вызывают достаточную головную боль и являются источникомвопросов, которые я назвал в # 3.Вы будете в порядке, если интерфейс между DLL и EXE является чистым интерфейсом "C".

  5. Проблемы искажения имени.Если вы столкнулись с проблемами, когда имя экспортируемой функции не совпадает из-за искажения имени или из-за начального подчеркивания, вы можете исправить это в файле .DEF.По крайней мере, это то, что я делал в прошлом с Visual Studio.Не уверен, существует ли эквивалент в g ​​++ / MinGW.Пример ниже.Научитесь использовать "dumpbin.exe / exports", чтобы вы могли проверить, экспортирует ли ваша DLL функция с правильным именем.Использование extern "C" также поможет исправить это.

     EXPORTS
      FooBar=_Foobar@12
      BlahBlah=??BlahBlah@@QAE@XZ @236 NONAME
    

Это те проблемы, которые я знаю.Я не могу сказать вам больше, так как вы не объяснили интерфейс между DLL и EXE.

1 голос
/ 04 февраля 2012

размер указателя не будет меняться; это зависит от разрядности платформы и модуля, а не от компилятора (32-разрядный или 64-разрядный и т. д.).

Что может варьироваться, так это размер в основном всего остального, а будет отличаться от шаблонов.

Заполнение и выравнивание структур, как правило, зависит от компилятора и часто зависит от настроек внутри компилятора. Существуют настолько свободные правила, как указатели, как правило, находящиеся на границе платформности и bool, имеющие 3 байта после них, но компилятору решать, как с этим справиться.

Шаблоны, особенно из STL (который отличается для каждого компилятора), могут иметь разные члены, размеры, отступы и, в основном, все что угодно. Единственная стандартная часть - это API, бэкэнд оставлен для реализации STL (есть некоторые правила, но компиляторы могут по-разному компилировать шаблоны). Передача шаблонов между модулями из одной сборки достаточно плоха, но между разными компиляторами это часто может быть фатальным.

Вещи, которые не стандартизированы (искажение имени) или весьма специфичны по необходимости (распределение памяти), также будут несовместимы. Обе эти проблемы можно обойти, только удалив из создавшей библиотеки (во всяком случае, хорошая практика) и используя объекты STL, для которых требуется средство удаления, для выделения и экспорта с использованием недекорированных имен и / или стиля C (extern "C") для экспортируемые методы.

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

Если вам удастся передать только ссылки на ваши собственные объекты, полностью избежать внешне видимых шаблонов, работать в основном с указателями и экспортированными или виртуальными методами, вы можете избежать подавляющего большинства проблем (COM делает именно это, для совместимости с большинство компиляторов и языков). Писать может быть больно, но если вам нужна такая совместимость, это возможно.

Чтобы устранить некоторые, но не все проблемы, использование альтернативы STL (например, базовой библиотеки Qt) устранит эту конкретную проблему. Бросить Qt в любой старый проект - отвратительная трата и вызовет больше раздувания, чем «повысить ВСЕ ВЕЩИ !!!» философия, это может быть полезно для разъединения библиотеки и компилятора в большей степени, чем использование стандартного STL.

0 голосов
/ 04 февраля 2012

Вы не можете передавать объекты времени выполнения C между ними. Например, вы не можете открыть буфер FILE в одном и передать его для использования в другом. Вы не можете освободить память, выделенную на другой стороне.

0 голосов
/ 04 февраля 2012

Основными проблемами являются сигнатуры функций и способы передачи параметров в код библиотеки. У меня были большие трудности с получением VC ++ dll для работы в компиляторах на основе gnu. Это было в далеком прошлом, когда VC ++ всегда стоил денег, а mingw был бесплатным решением.

Мой опыт был с DirectX API. Постепенно подмножество доработало свои двоичные файлы энтузиастами, но оно никогда не было таким современным и надежным, поэтому после оценки я переключился на надлежащий кроссплатформенный API, который был SDL.

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

...