Вы можете передать 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-файл.
Это иногда называют «внедрением зависимости» или «инверсией управления».