2010-07-09 40 views
5

我知道我们可以使用CoLoadLibrary和DllGetClassObject来获取IClassFactory接口并获得COM组件接口而无需注册DLL。EXE(进程外)COM服务器是否可以免注册激活?

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

回答

3

如果您使用实际registration free COM,您应该能够在进程内和进程外COM对象中使用此功能。

正如Sharptooth指出的,你真的没有使用免注册的COM。相反,通过伪造COM在激活过程中使用的调用,您真的可以自己动手了。如果您控制应用程序和您正在激活的COM服务器,但您的解决方案可以工作,但否则可能会失败。

+0

我不确定第一段是否正确,因为在它链接的文章中,唯一提及的进程外EXE服务器是说它们不能用于免注册的COM。 此线程也是有用的,并指出与免注册COM显然忽略管理的ROT的问题:http://social.msdn.microsoft.com/Forums/vstudio/en-US/3849f22d-c8b8-429e- a3a-37601411acec/registrationfree-exe-com-server- 似乎只有基本的进程内(也是非提升的)COM DLL对象受无reg机制的支持,对于任何更奇特的事情你必须自己推出自己的。 – 2013-09-03 16:30:20

+0

只有链接的答案非常糟糕,因为链接有消失的倾向......就像这个答案中的答案一样。 – Stephane 2016-07-22 14:04:26

1

您可以在函数调用中传递一个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进行。

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

+0

谢谢,我不知道我对你的解决方案有多了解,看起来像是一种替代方式:1.启动EXE,并将对象指向基于DLL的COM组件。 2.当我需要使用对象EXE实现组件时,我应该通过DLL组件实现一个指针,它包含在EXE文件中实现的Component。 我收到了吗? – Gohan 2010-07-12 11:17:59

+0

我想我理解你,我相信你已经明白了。 – 2010-07-12 11:45:06

2

不,你不能。您需要在您的程序和out-proc COM服务器之间进行COM设置编组。要达到此目的,您必须拨打CoInitialize(),然后拨打CoCreateInstance()CoGetClassObject()

你一个进程内服务器描述的路径 - 呼叫CoLoadLibrary()然后DllGetClassObject() - 事实上是一个肮脏的黑客 - 它绕过正常的COM等机制,例如即使需要它来满足线程没有编组将在踢模型要求(STA/MTA的东西)。这种肮脏的黑客攻击是可能的,因为进程内服务器是一个常规的DLL,其中有几个众所周知的功能暴露出来。对于一个out-proc COM服务器来说,这是不可能的 - 在这种情况下,您需要依赖COM。

相关问题