Имитация SideBySide для внепроцессного ActiveX
-
20-09-2019 - |
Вопрос
Мы адаптируем наше относительно сложное приложение на стороне клиента (ActiveX / .net / Delphi / C ++ / COM ) для использования SxS для обеспечения развертывания без участия администратора и изоляции от более старых версий нашего продукта.
Мы смогли достичь этой цели почти для всех наших компонентов in proc, таких как наш .net ui, Delphi ui и COM-серверы, которые мы используем в proc, создав файл манифеста, в котором описаны все библиотеки, используемые нашим процессом, без регистрации на клиенте какого-либо из компонентов (почти).
И вот начинается часть " почти ":На данный момент наше приложение вызывает (из своей части c ++) сервер out of proc ActiveX (Delphi ActiveX EXE), который, в свою очередь, сам вызывает другой набор серверов out of proc ActiveX (плагины сторонних производителей, здесь подходит все, Delphi, C ++, любая вещь, если она находится вне proc ActiveX EXE и реализует наши интерфейсы).
Как мы знаем SxS не поддерживает серверы ActiveX вне proc.И мы не можем использовать эти объекты, как на серверах proc com, в нашем основном процессе, потому что это потребовало бы серьезной перезаписи нашего приложения и, что еще хуже, взлома нашего общедоступного API, который используется сторонними инструментами и поставщиками, взлома API, который мы не можем допустить.
Мы наткнулись на эта статья в котором описывается, как IHTMLDocument2 может быть извлечен из окна Internet Explorer, запущенного в отдельном процессе.Что заставило нас задуматься об этом подходе:
Мы бы создали вторичное приложение-спутник / процесс, который будет запускать ActiveX как на process server.Затем мы будем использовать Lрезультат из объекта и Объект из результата для передачи ссылки на объект ActiveX из вспомогательного приложения в основной процесс приложения.Приложение satellite будет иметь собственный файл манифеста, который позволит ему запускаться в режиме SxS.
Такой же подход будет применен для обмена данными между этим Delphi ActiveX EXE и сторонними плагинами AciveX EXE
Существует альтернативное решение, которое на данный момент мы не предпочитаем предложенному выше решению, которое заключается в использовании прокси-классов .net remoting и .net com для открытия канала связи между двумя процессами путем перевода com-запроса в .net remoting и обратно в com во втором процессе.
Итак, здесь возникает вопрос:
- Что вы думаете о таком подходе ?
- Видите ли вы лучшее решение этой проблемы ?
Решение
Это вполне возможно сделать.Что необходимо:
- Приложение должно само запускать сервер, а не полагаться для этого на COM.Вам не нужно дополнительное косвенное обращение, предоставляемое реестром, просто используйте CreateProcess().
- Сервер должен зарегистрировать свои фабрики классов в своем методе main() с помощью CoRegisterClassObject().
- Важный:идентификатор CLSID, который он использует для каждой фабрики, должен быть изменен, чтобы быть уникальным для каждого экземпляра службы.Это гарантирует, что клиент подключится к правильному серверу.Я просто заменяю идентификатор процесса на CLSID фабрики классов.Клиент также знает идентификатор процесса, поэтому может внести такое же изменение.
- Приложение должно вызвать CoCreateInstance() в цикле с вызовом Sleep(), чтобы дождаться появления фабрики объектов.Не объявляйте о сбое, пока не пройдет по крайней мере 60 секунд (это меня задело).
- И приложению, и серверу нужен манифест, содержащий
<file>
элемент для каждого прокси/заглушки DLL и<comInterfaceExternProxyStub>
элементы для каждого удаленного интерфейса.
Другие советы
Алекс,
нобугз прав, вы можете получить доступ к таблице запущенных объектов, чтобы создать экземпляр COM-объекта из текущего запущенного процесса вашего Delphi automation exe.
Однако я обнаружил большую проблему, которую я не могу объяснить.При работе таким образом я могу получить доступ к объекту только через метод variant dispatch.
В принципе, если мой Активный X exe не зарегистрирован, я получаю ошибку "Интерфейс не поддерживается", если я пытаюсь создать экземпляр объекта через интерфейсы, например:
Веб-обновление :Иавтоматизация;
WebUpdate := Совместное обновление.Создать;<-- Ошибка не будет работать
Веб-обновление :Вариант;
Веб-обновление:= CreateOleObject('Веб-обновление.Автоматизация');<-- Работает нормально
Если я зарегистрирую активный x exe-файл с помощью regserver, проблема исчезнет!!
Поди разберись!