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

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

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

7
задан Shog9 9 July 2010 в 19:51
поделиться

3 ответа

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

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

3
ответ дан 7 December 2019 в 09:55
поделиться

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

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

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

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

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

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

Обновление

Более полное решение - определить стандартный способ создания экземпляра типа объекта, но позволить EXE определить, как это работает. EXE будет реализовывать:

interface IComponent;

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

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

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

Теперь, чтобы получить стандартное поведение, когда EXE хочет использовать реестр для поиска компонентов, он может реализовать метод 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;
}

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

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

// 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...

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

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

1
ответ дан 7 December 2019 в 09:55
поделиться

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

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

2
ответ дан 7 December 2019 в 09:55
поделиться
Другие вопросы по тегам:

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