您可以在函数调用中将 COM 组件作为指针传递。
因此,假设您在 EXE 中实现了一个对象,并从 DLL 加载另一个 COM 对象,您可以将基于 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 进行。
这有时被称为“依赖注入”或“控制反转”。