EXE(进程外)COM服务器是否可以免注册激活?

EXE(进程外)COM服务器是否可以免注册激活?,com,dll,winapi,regfreecom,Com,Dll,Winapi,Regfreecom,我知道我们可以使用CoLoadLibrary和DllGetClassObject来获取IClassFactory接口和COM组件接口,而无需注册DLL 但是EXE中的COM组件呢?有没有一种方法可以通过提供不同的文件路径从EXE类型的COM服务器获取COM组件接口?您可以在函数调用中传递COM组件作为指针 因此,假设您在EXE中实现了一个对象,并且从DLL加载了另一个COM对象,您可以将基于EXE的对象从DLL传递给该对象。加载的对象需要支持具有接受指针的函数的接口,例如 interface I

我知道我们可以使用CoLoadLibrary和DllGetClassObject来获取IClassFactory接口和COM组件接口,而无需注册DLL


但是EXE中的COM组件呢?有没有一种方法可以通过提供不同的文件路径从EXE类型的COM服务器获取COM组件接口?

您可以在函数调用中传递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...
由于每个组件在创建时都会收到环境通知,因此它可以使用环境来创建其他组件:

// 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...
//某些组件内部:
HRESULT组件::设置环境(IEnEnvironment*e)
{
m_env=e;//使用智能指针进行ref计数
返回S_OK;
}
//在组件的某些方法中
ComPtr按钮;
m_env->CreateInstance(CLSID_按钮和按钮);
//现在查询更有用的界面按钮。。。
因此,无论何时创建组件,环境(在EXE中定义)都可以精确地控制如何找到组件的实现。每个创建都通过EXE进行


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

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

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

如果您使用real,您应该能够使其同时适用于in-proc和out-proc-COM对象


正如Sharptooth指出的,您实际上没有使用免注册COM。相反,你通过假装COM在激活过程中使用的调用来实现自己的目的。如果您同时控制您的应用程序和正在激活的COM服务器,您的解决方案可以正常工作,但否则很可能会失败。

谢谢,我不知道我对您的解决方案有多了解,看起来这是另一种方法:1。启动EXE并将对象点放在基于DLL的COM组件上。2.当我需要使用对象EXE实现组件时,我应该通过DLL组件获得它,该组件实现一个指针容器,其中包含在EXE文件中实现的组件。我明白了吗?我想我理解你,我相信你明白了。我不确定第一段是不是真的,因为在它链接到的文章中,唯一提到进程外的EXE服务器是说它们不能与免注册COM一起使用。这个线程也很有用,它指出了ROT的问题,而免费注册的COM显然忽略了它的管理:似乎只是基本的、进程中的(也是非提升的)COM DLL对象受reg free机制支持,对于任何更奇特的对象,您必须自己滚动。仅链接的答案非常糟糕,因为链接有消失的趋势。。。正如Stephane所说,答案中的链接不再有效;然而,这似乎是2005年4月版MSDN杂志上的一篇文章。您可以从重定向到的页面下载整期MSDN杂志。正如利奥·戴维森(Leo Davidson)所指出的,这篇文章从完整的期刊档案中阅读,指出基于EXE的服务器会取消COM服务器注册免费COM的资格。我不确定的是,是否存在允许基于DLL的免注册COM的机制,该DLL可以在proc中运行,也可以在proc外运行。