Ну, я думаю предложение Криса Бекке просто отлично. Я бы не стал использовать первое решение Роджера , которое использует интерфейс только по имени и, как он упоминает, может столкнуться с проблемами несовместимой обработки компилятором абстрактных классов и виртуальных методов. Роджер указывает на привлекательный COM-совместимый случай в его последующем .
Суть проблемы: вам нужно научиться делать запросы интерфейса COM и правильно обрабатывать IUnknown, полагаясь как минимум на IUnknown: AddRef и IUnknown: Release. Если реализации интерфейсов могут поддерживать более одного интерфейса или если методы также могут возвращать интерфейсы, вам также может понадобиться освоить IUnknown: QueryInterface.
Вот ключевая идея. Все программы, которые используют реализацию интерфейса (но не реализуют его), используют общий файл #include "* .h", который определяет интерфейс как struct (C) или класс C / C ++ (VC ++) или структура (не VC ++, но C ++). Файл * .h автоматически адаптируется соответствующим образом в зависимости от того, компилируете ли вы программу на языке C или программу на языке C ++. Вам не нужно знать об этой части просто, чтобы использовать файл * .h. Что делает файл * .h, так это определяет структуру или тип интерфейса, скажем, IFoo, с его виртуальными функциями-членами (и только функциями, без прямой видимости для элементов данных в этом подходе).
Заголовочный файл сконструирован так, чтобы соответствовать двоичному стандарту COM таким образом, чтобы он работал на C и работал на C ++ независимо от используемого компилятора C ++. (Народ Java JNI понял это.) Это означает, что он работает между отдельно скомпилированными модулями любого происхождения, при условии, что структура, состоящая полностью из указателей на ввод функций (vtable), отображается всеми в одну и ту же память (таким образом, они должны быть все 32-разрядные x86, или все x64, например).
В DLL, которая реализует интерфейс COM через некоторый класс-оболочку, вам нужна только фабричная точка входа. Что-то вроде
extern "C" HRESULT MkIFooImplementation (void ** ppv);
, который возвращает HRESULT (вам тоже нужно узнать о них), а также вернет * pv в месте, которое вы указали для получения указателя интерфейса IFoo. (Я делаю снимки, и здесь вам понадобятся более подробные детали. Не доверяйте моему синтаксису) Фактический стереотип функции, который вы используете для этого, также объявлен в файле * .h.
Суть в том, что фабричная запись, которая всегда является неоткрытым внешним элементом "C", выполняет все необходимые операции создания класса-оболочки и затем доставляет указатель интерфейса Ifoo в указанное вами местоположение. Это означает, что все управление памятью для создания класса и все управление памятью для его завершения и т. Д. Будут происходить в DLL, где вы создаете оболочку. Это единственное место, где вам приходится иметь дело с этими деталями.
Когда вы получаете результат OK от заводской функции, вам был выдан указатель интерфейса, и он уже зарезервирован для вас (существует неявная операция IFoo: Addref, уже выполненная от имени указателя интерфейса, который вы были доставлены).
Когда вы закончили работу с интерфейсом, вы освобождаете его вызовом метода IFoo: Release интерфейса. Это окончательная реализация релиза (если вы сделали больше копий AddRef'd), которая разрушит класс и его интерфейсную поддержку в заводской DLL. Это то, что дает вам правильную зависимость от согласованного динамического распределения и освобождения хранилища за интерфейсом, независимо от того, использует ли библиотека DLL, содержащая функцию фабрики, те же библиотеки, что и вызывающий код.
Вы, вероятно, должны также реализовать IUnknown: QueryInterface (как метод IFoo: QueryInterface), даже если он всегда терпит неудачу. Если вы хотите быть более изощренными с использованием модели двоичного интерфейса COM, поскольку у вас больше опыта, вы можете научиться предоставлять полные реализации QueryInterface.
Это, вероятно, слишком много информации, но я хотел бы отметить, что многие проблемы, с которыми вы сталкиваетесь в гетерогенных реализациях DLL, решаются в определении двоичного интерфейса COM, и даже если вам не нужны все это, тот факт, что он предоставляет работающие решения является ценным. По моему опыту, как только вы это освоите, вы никогда не забудете, насколько мощным это может быть в ситуациях взаимодействия C ++ и C ++.
Я не набросал ресурсы, к которым вам, возможно, нужно обращаться за примерами, и что вы должны изучить, чтобы создавать файлы * .h и фактически реализовывать фабрично-функциональные оболочки библиотек, которыми вы хотите поделиться. Если хочешь копать глубже, кричи.