Is registration-free activation possible for EXE (out-of-process) COM servers?
Asked Answered
G

4

9

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?

Greerson answered 9/7, 2010 at 9:22 Comment(0)
H
3

If you use the real registration free COM, you should be able to get this working for both in-proc and out-of-proc COM objects.

As Sharptooth pointed out, you're really not using registration free COM. Instead you're really rolling your own by faking the calls that COM uses during activation. Your solution CAN work if you control both your application and the COM server you're activating but it's likely to fail otherwise.

Hurryscurry answered 10/7, 2010 at 4:20 Comment(3)
I am not sure the first paragraph is true as, in the article it links to, the only mentions of out-of-process EXE servers are to say that they cannot be used with registration-free COM. This thread is also useful and points to issues with the ROT which registration-free COM apparently neglects to manage: social.msdn.microsoft.com/Forums/vstudio/en-US/… Seems like only basic, in-process (also non-elevated) COM DLL objects are supported by the reg-free mechanism and for anything more exotic you have to roll your own.Aarau
Link-only answers are really bad since links have a tendency to disappear... like the one in this answer.Zaidazailer
As Stephane noted, The link in the answer no longer works; however, it appears to be to an article in the April 2005 edition of MSDN Magazine. One can download the entire issue of MSDN Magazine from the page one is redirected to. As Leo Davidson noted, the article, as read from the full-issue archive, notes that being an EXE-based Server disqualifies the COM server from registration-free COM. What I'm uncertain of is whether there exists some mechanism to allow registration-free COM based on a DLL that can run in-or-out-of-proc.Taxidermy
C
2

No, you cannot. You need COM setup marshalling between your program and out-proc COM server. To achieve this you have to call CoInitialize() and then either CoCreateInstance() or CoGetClassObject().

The path you describe with an in-proc server - calling CoLoadLibrary() and then DllGetClassObject() - is in fact a dirty hack - it bypasses normal COM mechanisms and so for example no marshalling will kick in even if it is needed to satisfy threading model requirements (STA/MTA stuff). Such dirty hack is possible because an in-proc server is a regular DLL with several well-known functions exposed. The same is impossible for an out-proc COM server - you need to rely on COM in that case.

Chockablock answered 9/7, 2010 at 9:47 Comment(0)
H
1

You can pass a COM component in a function call, as a pointer.

So suppose you implement an object in your EXE, and that loads another COM object from a DLL, you can pass the EXE-based object to the object from the DLL. The loaded object would need to support an interface that has a function which accepts a pointer, e.g.

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

If the DLL-based object implements that, you can call it from your EXE and pass it an object that is not registered anywhere, so there is no need to register objects in an EXE to achieve this.

The only requirements are on the correct implementation of IUnknown: don't destroy the object until Release has been called the right number of times, and ensure that QueryInterface can be used to traverse between a fixed set of interfaces on the object and that querying for IUnknown always returns the same address.

On the other hand, you can register an EXE as a server of objects, but that introduces a lot of complexity; COM has to start the EXE running and then send it messages via the Windows message queue. This is only widely used for OLE; it can be quite fragile.

Update

A more complete solution is to define a standard way to create an instance of an object type, but to allow the EXE to define how it works. The EXE would implement:

interface IComponent;

interface IEnvironment : IUnknown
{
    HRESULT CreateInstance(REFCLSID clsid, IComponent **ppNew);
}

Every component must support this interface:

interface IComponent : IUnknown
{
    HRESULT SetEnvironment(IEnvironment *pEnv);
}

Now, to get the standard behaviour where the EXE wants to use the registry to find components, it can implement the CreateInstance method like this:

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;
}

But of course it can change this and "inject" some components. So instead of (or in addition to) the registry, a configuration file may be used. Or (as you've asked) the EXE could have built-in implementations of some components:

Because every component is notified of the environment when it is created, it can use the environment to create further components:

// 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...

So whenever a component is created, the environment (defined in the EXE) can control exactly how the implementation of the component is found. Every creation goes via the EXE.

This is sometimes called "dependency injection" or "inversion of control".

Hirz answered 9/7, 2010 at 9:29 Comment(2)
Thanks, I don't know how much I understand your solution, looks like that is a alternative way: 1. start EXE and put the object point at a DLL based COM Component. 2. when I need using the object EXE implement Component, I should get it through the DLL Component which implement a pointer Container contains Component implemented in the EXE files. Have I got it?Greerson
I think I understand you and I believe you have got it.Hirz
G
0

Actually, the answer is Yes! Assuming you have a COM server EXE that is capable of self-registration (typically via /regserver parameter), but you want to use it without registering, this should work:

  1. Launch the COM EXE server with the parameters "/automation -Embedding". Parameters can vary depending on the tools used to build the COM EXE, but these parameters are typical.

  2. In a client, instantiate the COM object using the CLSID (GUID), not the friendly PROGID. If your dev tools only support PROGID, you may be able to use the Windows API CoCreateInstance().

Interestingly, the answer was provided by Larry Osterman himself. In his blog post from 2005, he points out: "When COM tries to activate a COM object, before it looks in the registry, it looks to see if there’s a server already registered for that class." Launching the EXE with the requisite parameters registers out-of-process COM objects in memory with the Windows COM/OLE system. Clients should find them even though they aren't in the Windows registry.

More info: Reg-Free COM with Out-of-Process Servers

Greaseball answered 26/7, 2023 at 19:28 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.