Возможна ли активация без регистрации для COM-серверов EXE (вне процесса)?

StackOverflow https://stackoverflow.com/questions/3211345

  •  13-09-2020
  •  | 
  •  

Вопрос

Я знаю, что мы можем использовать CoLoadLibrary и DllGetClassObject, чтобы получить интерфейс IClassFactory и получить интерфейс COM-компонента без регистрации библиотеки DLL.

Но как насчет COM-компонента в исполняемом файле?Есть ли способ, которым я могу получить интерфейс COM-компонента с COM-сервера EXE-типа, просто указав другой путь к файлу?

Это было полезно?

Решение

Если вы используете реальные Регистрация Бесплатный COM, вы должны быть в состоянии получить эту работу как для OR-PREC, так и для OUT-COM-объектов.

Как указал Sharptooth, вы действительно не используете бесплатный COM.Вместо этого вы действительно катитесь своими собственными, притворяющие звонки, которые используют во время активации.Ваше решение может работать, если вы управляете как вашим приложением, так и COM-сервер, который вы активируетесь, но может потерпеть неудачу в противном случае.

Другие советы

Нет, ты не можешь.Вам нужна настройка COM-соединения между вашей программой и внешним COM-сервером.Чтобы достичь этого, вы должны вызвать CoInitialize() и тогда либо CoCreateInstance() или CoGetClassObject().

Путь, который вы описываете с помощью вызова сервера in-proc CoLoadLibrary() и затем DllGetClassObject() - на самом деле это грязный взлом - он обходит обычные механизмы COM, и поэтому, например, маршалинг не сработает, даже если это необходимо для удовлетворения требований потоковой модели (STA / MTA).Такой грязный взлом возможен потому, что сервер in-proc представляет собой обычную библиотеку DLL с несколькими хорошо известными функциями.То же самое невозможно для стороннего COM-сервера - в этом случае вам нужно полагаться на COM.

Вы можете передать COM-компонент при вызове функции в качестве указателя.

Итак, предположим, вы реализуете объект в своем исполняемом файле, и это загружает другой COM-объект из библиотеки DLL, вы можете передать объект на основе EXE объекту из библиотеки DLL.Загруженный объект должен был бы поддерживать интерфейс, имеющий функцию, которая принимает указатель, например

interface ILoadedObject
{
    HRESULT GiveObject(IUnknown *pObj);
};

Если объект на основе DLL реализует это, вы можете вызвать его из своего исполняемого файла и передать ему объект который нигде не зарегистрирован, поэтому для достижения этой цели нет необходимости регистрировать объекты в исполняемом файле.

Единственные требования заключаются в правильном выполнении IUnknown:не уничтожайте объект до тех пор, пока Release был вызван нужное количество раз, и убедитесь, что QueryInterface может использоваться для перехода между фиксированным набором интерфейсов объекта и этим запросом для IUnknown всегда возвращает один и тот же адрес.

С другой стороны, вы можете зарегистрировать исполняемый файл в качестве сервера объектов, но это создает большую сложность;COM должен запустить исполняемый файл, а затем отправлять ему сообщения через очередь сообщений Windows.Это широко используется только для OLE;она может быть довольно хрупкой.

Обновление

Более полным решением является определение стандартного способа создания экземпляра типа object, но позволяющего исполняемому файлу определять, как это работает.Исполняемый файл будет реализовывать:

interface IComponent;

interface IEnvironment : IUnknown
{
    HRESULT CreateInstance(REFCLSID clsid, IComponent **ppNew);
}

Каждый компонент должен поддерживать этот интерфейс:

interface IComponent : IUnknown
{
    HRESULT SetEnvironment(IEnvironment *pEnv);
}

Теперь, чтобы получить стандартное поведение, при котором исполняемый файл хочет использовать реестр для поиска компонентов, он может реализовать CreateInstance метод, подобный этому:

HRESULT Env::CreateInstance(REFCLSID clsid, IComponent **ppNew)
{
    HRESULT hr = CoCreateInstance(clsid, NULL, CLSCTX_INPROC_SERVER,
                     __uuidof(IComponent), (void **)&ppNew);
    if (FAILED(hr))
        return hr;

    (*ppNew)->SetEnvironment(this);
    return S_OK;
}

Но, конечно, он может изменить это и "внедрить" некоторые компоненты.Таким образом, вместо реестра (или в дополнение к нему) может использоваться файл конфигурации.Или (как вы спросили) исполняемый файл мог бы иметь встроенные реализации некоторых компонентов:

Поскольку каждый компонент получает уведомление о среде при ее создании, он может использовать среду для создания других компонентов:

// inside some component:
HRESULT Comp::SetEnvironment(IEnvironment *e)
{
    m_env = e; // using a smart pointer for ref-counting
    return S_OK;
}

// in some method of the component

ComPtr<IComponent> button;
m_env->CreateInstance(CLSID_Button, &button);

// now query button for more useful interface...

Таким образом, всякий раз, когда создается компонент, среда (определенная в исполняемом файле) может точно контролировать, как будет найдена реализация компонента.Каждое создание выполняется через исполняемый файл.

Это иногда называют "внедрением зависимостей" или "инверсией контроля".

Лицензировано под: CC-BY-SA с атрибуция
Не связан с StackOverflow
scroll top