Используя C++ DLLs с различными версиями компилятора

После некоторых раздумий я понял, в чем проблема в конце.

Похоже, что mongodb в Windows может запускаться как локальный сервис, который запускает базу данных на 127.0.0.1:27017.

Таким образом, используя Robo3T, я подключался к этому локальному экземпляру, а не к своему подключенному экземпляру Docker Mongo. С Robo3T я мог подключиться к этому локальному экземпляру, когда снял флажок «Выполнить аутентификацию».

В Robo3T вы можете выбрать -> щелкните правой кнопкой мыши «Открыть оболочку» -> db.hostInfo() -> F5 -> Просмотреть результаты в текстовом режиме. Это даст информацию о моем настольном компьютере

, тогда как docker exec -it mongodb mongo --eval 'db.hostInfo()' будет отображать информацию, касающуюся моего изображения докера.

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

Это позволило бы docker run -p 27017:27017 -it --name mongodb <myregistry>.azurecr.io/movo.mongodb привязаться к моему док-контейнеру в 127.0.0.1:27017

6
задан Community 23 May 2017 в 12:00
поделиться

5 ответов

Интерфейсные имена элемента не будут украшены - они - просто смещения в vtable. Можно определить интерфейс (использование структуры C, а не COM "интерфейс") в заголовочном файле, таким образом:

struct IFoo {
    int Init() = 0;
};

Затем можно экспортировать функцию из DLL без искажения:

class CFoo : public IFoo { /* ... */ };
extern "C" IFoo * __stdcall GetFoo() { return new CFoo(); }

Это будет хорошо работать, при условии, что Вы используете компилятор, который генерирует совместимый vtables. Microsoft C ++ генерировал тот же формат, vtable с тех пор (по крайней мере, я думаю), MSVC6.1 для DOS, где vtable является простой список указателей на функции (с преобразованием в случае множественного наследования). GNU C++ (если я вспоминаю правильно) генерирует vtables с указателями функции и относительными смещениями. Они не совместимы друг с другом.

3
ответ дан 8 December 2019 в 17:29
поделиться

Самой большой проблемой для рассмотрения при использовании DLL, скомпилированного с другим компилятором C++, чем вызов EXE, является выделение памяти и объектное время жизни.

Я предполагаю, что можно закончить искажение имени (и соглашение о вызовах), который не является трудным, если Вы используете компилятор с совместимым искажением (я думаю, что VC6 широко совместим с VS2008), или если Вы используете экстерна "C".

То, где Вы столкнетесь с проблемами, - когда Вы выделяете что-то использование new (или malloc) от DLL, и затем Вы возвращаете это вызывающей стороне. Вызывающая сторона delete (или free) попытается освободить объект от другой "кучи". Это пойдет ужасно неправильно.

Можно или сделать COM-стиль IFoo::Release вещь или a MyDllFree() вещь. Оба из них, потому что они перезванивают в DLL, будут использовать корректную реализацию delete (или free()), таким образом, они удалят правильный объект.

Или, можно удостовериться, что Вы используете LocalAlloc (например), так, чтобы EXE и DLL используют ту же "кучу".

7
ответ дан 8 December 2019 в 17:29
поделиться

Существуют другие вещи, которые необходимо рассмотреть также, такой как, какое время выполнения используется различными библиотеками. Если никакие объекты не совместно используются, это прекрасно, но это кажется довольно маловероятным на первый взгляд.
Предложения Chris Becker довольно точны - использование фактического COM-интерфейса может помочь Вам получить совместимость на уровне двоичных кодов, в которой Вы нуждаетесь. Ваш пробег может варьироваться :)

1
ответ дан 8 December 2019 в 17:29
поделиться

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

Единственное решение состояло бы в том, чтобы записать интерфейс DLL C-стиля с помощью обработчиков для объектов, или я пропускаю что-то? В этом случае я предполагаю, у меня, вероятно, было бы меньше усилия с прямым использованием перенесенной C-библиотеки.

действительно внимательный взгляд.удачи.

0
ответ дан 8 December 2019 в 17:29
поделиться

Ну, я думаю, что предложение Chris Becke очень хорошо. Я не использовал бы первое решение Roger, которое использует интерфейс только номинально и, как он упоминает, может столкнуться с проблемами несовместимой обработки компилятора абстрактных классов и виртуальных методов. Roger указывает на привлекательный COM-последовательный случай в своем последующем.

  1. Болевая точка: необходимо учиться выполнять запросы COM-интерфейса и иметь дело правильно с IUnknown, полагаясь, по крайней мере, на IUnknown:AddRef и IUnknown:Release. Если реализации интерфейсов могут поддерживать больше чем один интерфейс или если методы могут также возвратить интерфейсы, Вы, возможно, также должны стать довольными IUnknown:QueryInterface.

  2. Вот ключевая идея. Все программы, которые используют реализацию интерфейса (но не реализуют его) используют общий #include "*.h" файл, который определяет интерфейс как структуру (C) или класс C/C++ (VC ++) или структуру (не VC ++, но C++). *.h файл автоматически адаптируется соответственно в зависимости от того, компилируете ли Вы программу языка C или программу языка C++. Вы не должны знать о той части просто для использования *.h файла. То, что делает *.h файл, определяют Интерфейсную структуру или тип, позволяет, говорят, IFoo, с его виртуальными функциями членства (и только функционирует, никакая прямая видимость к элементам данных в этом подходе).

  3. Заголовочный файл создается для удостаивания двоичного стандарта COM способом, который работает на C, и это работает на C++ независимо от компилятора C++, который используется. (Java народ JNI понял этого.) Это означает, что работает между отдельно-скомпилированными-модулями любого источника, пока структура, состоящая полностью из указателей функциональной записи (vtable), отображается на памяти то же всеми ими (таким образом, они должны быть всеми x86 32-разрядный, или весь x64, например).

  4. В DLL, который реализует COM-интерфейс через какой-то класс обертки, Вам только нужна точка входа фабрики. Что-то как

    MkIFooImplementation экстерна "C" HRESULT (освобождают ** ppv);

который возвращает HRESULT (необходимо будет узнать о тех также), и также возвратится *объем плазмы в месте, Вы предусматриваете получение указателя на интерфейс IFoo. (Я скольжу и существуют более осторожные детали, в которых Вы будете нуждаться здесь. Не доверяйте моему синтаксису), фактический функциональный стереотип, который Вы используете для этого, также объявляется в *.h файле.

  1. Дело в том, что запись фабрики, которая всегда является нетитулованным экстерном "C", делает все необходимое создание класса обертки и затем обеспечивает указатель на интерфейс Ifoo местоположению, которое Вы указываете. Это означает, что все управление памятью для создания класса и все управление памятью для завершения его, и т.д., произойдут в DLL, где Вы создаете обертку. Это - единственное место, где необходимо иметь дело с теми деталями.

  2. Когда Вы получаете результат OK функции фабрики, Вы были выпущены указатель на интерфейс, и она была уже зарезервирована для Вас (существует неявная операция IFoo:Addref, уже выполненная от имени указателя на интерфейс, который Вам поставили).

  3. Когда Вы сделаны с интерфейсом, Вы выпускаете его с запросом к методу IFoo:Release интерфейса. Это - реализация финальной версии (в случае, если Вы сделали больше копий AddRef'd), который разъединит класс и его интерфейсную поддержку на фабрике DLL. Это - то, что получает Вас корректная зависимость от последовательного динамического выделения устройства хранения данных и выпуска позади интерфейса, пользуется ли DLL, содержащий функцию фабрики, теми же библиотеками как код вызова.

  4. Необходимо, вероятно, реализовать IUnknown:QueryInterface (как метод IFoo:QueryInterface) также, даже если он всегда перестал работать. Если Вы хотите быть более сложными с использованием двоичной интерфейсной модели COM, поскольку у Вас есть больше опыта, можно учиться обеспечивать полные реализации QueryInterface.

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

Я не делал набросок ресурсов, с которыми Вы, возможно, должны были бы консультироваться для примеров и что необходимо изучить для создания *.h файлов и на самом деле реализовать функциональные фабрикой обертки библиотек, которые Вы хотите совместно использовать. Если Вы хотите вырыть глубже, кричать.

3
ответ дан 8 December 2019 в 17:29
поделиться
Другие вопросы по тегам:

Похожие вопросы: