7

I know that we can use CoLoadLibrary and DllGetClassObject to get the IClassFactory interface and get the COM component interface without registering the DLL.

But what about a COM component in an EXE? Is there a way that I can get a COM component interface from an EXE-type COM server by just providing a different file path?

4

3 回答 3

3

如果您使用真正的 免费注册 COM,您应该能够让这个在进程内和进程外 COM 对象上工作。

正如 Sharptooth 指出的那样,您实际上并没有使用免注册 COM。相反,您实际上是在通过伪造 COM 在激活期间使用的调用来实现自己的目标。如果您同时控制您的应用程序和您正在激活的 COM 服务器,您的解决方案可以工作,但否则它可能会失败。

于 2010-07-10T04:20:11.913 回答
2

你不能。您需要在程序和 out-proc COM 服务器之间进行 COM 设置编组。要实现这一点,您必须先调用CoInitialize(),然后调用CoCreateInstance()or CoGetClassObject()

您使用进程内服务器描述的路径 - 调用CoLoadLibrary()然后DllGetClassObject()- 实际上是一个肮脏的黑客 - 它绕过正常的 COM 机制,因此例如,即使需要满足线程模型要求(STA/MTA)也不会启动编组东西)。这种肮脏的黑客攻击是可能的,因为进程内服务器是一个常规的 DLL,暴露了几个众所周知的函数。对于进程外 COM 服务器来说,同样的事情是不可能的——在这种情况下,您需要依赖 COM。

于 2010-07-09T09:47:49.157 回答
1

您可以在函数调用中将 COM 组件作为指针传递。

因此,假设您在 EXE 中实现了一个对象,并从 DLL 加载另一个 COM 对象,您可以将基于 EXE 的对象传递给 DLL 中的对象。加载的对象需要支持具有接受指针的函数的接口,例如

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

如果基于 DLL 的对象实现了这一点,您可以从您的 EXE 中调用它并传递一个未在任何地方注册的对象,因此无需在 EXE 中注册对象即可实现此目的。

唯一的要求是正确实现:在被调用正确次数IUnknown之前不要破坏对象,并确保可用于在对象上的一组固定接口之间遍历,并且查询始终返回同一个地址。ReleaseQueryInterfaceIUnknown

另一方面,您可以将 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 进行。

这有时被称为“依赖注入”或“控制反转”。

于 2010-07-09T09:29:32.273 回答