Pergunta

Eu sei que podemos usar CoLoadLibrary e DllGetClassObject para obter a interface IClassFactory e obter a interface do componente COM sem registrar a DLL.

Mas e quanto a um componente COM em um EXE?Existe uma maneira de obter uma interface de componente COM de um servidor COM do tipo EXE apenas fornecendo um caminho de arquivo diferente?

Foi útil?

Solução

Se você usar o real registro livre de registro, você deve ser capaz de fazer isso funcionando tanto para objetos COM PROC quanto para fora do Proc.

Como Sharptooth apontou, você realmente não está usando o registro livre de registro.Em vez disso, você está realmente revirando o seu próprio fingindo as chamadas que COM usa durante a ativação.Sua solução pode funcionar se você controlar seu aplicativo e o servidor COM você está ativando, mas é provável que falhe de outra forma.

Outras dicas

Não, você não pode.Você precisa de um empacotamento de configuração COM entre o seu programa e o servidor COM out-proc.Para conseguir isso você tem que ligar CoInitialize() e então também CoCreateInstance() ou CoGetClassObject().

O caminho que você descreve com um servidor in-proc - chamando CoLoadLibrary() e então DllGetClassObject() - é na verdade um hack sujo - ele ignora os mecanismos COM normais e, por exemplo, nenhum empacotamento será ativado, mesmo que seja necessário para satisfazer os requisitos do modelo de threading (coisas STA/MTA).Esse hack sujo é possível porque um servidor em processo é uma DLL normal com várias funções conhecidas expostas.O mesmo é impossível para um servidor COM out-proc - nesse caso, você precisa confiar no COM.

Você pode passar um componente COM em uma chamada de função, como um ponteiro.

Então, suponha que você implemente um objeto em seu EXE e carregue outro objeto COM de uma DLL, você pode passar o objeto baseado em EXE para o objeto da DLL.O objeto carregado precisaria suportar uma interface que possui uma função que aceita um ponteiro, por exemplo.

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

Se o objeto baseado em DLL implementar isso, você poderá chamá-lo do seu EXE e passar um objeto para ele que não está registrado em lugar nenhum, portanto não há necessidade de registrar objetos em um EXE para conseguir isso.

Os únicos requisitos dizem respeito à correcta implementação de IUnknown:não destrua o objeto até Release foi chamado o número certo de vezes e garanta que QueryInterface pode ser usado para percorrer entre um conjunto fixo de interfaces no objeto e aquela consulta por IUnknown sempre retorna o mesmo endereço.

Por outro lado, você pode registrar um EXE como servidor de objetos, mas isso apresenta muita complexidade;COM tem que iniciar o EXE em execução e, em seguida, enviar mensagens através da fila de mensagens do Windows.Isso é amplamente utilizado apenas para OLE;pode ser bastante frágil.

Atualizar

Uma solução mais completa é definir uma forma padrão de criar uma instância de um tipo de objeto, mas permitir que o EXE defina como ele funciona.O EXE implementaria:

interface IComponent;

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

Cada componente deve suportar esta interface:

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

Agora, para obter o comportamento padrão onde o EXE deseja usar o registro para localizar componentes, ele pode implementar o CreateInstance método como este:

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

Mas é claro que pode mudar isso e “injetar” alguns componentes.Portanto, em vez (ou além) do registro, um arquivo de configuração pode ser usado.Ou (como você pediu) o EXE poderia ter implementações internas de alguns componentes:

Como cada componente é notificado sobre o ambiente quando é criado, ele pode usar o ambiente para criar outros componentes:

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

Assim sempre que um componente é criado, o ambiente (definido no EXE) pode controlar exatamente como a implementação do componente é encontrada.Toda criação passa pelo EXE.

Isso às vezes é chamado de “injeção de dependência” ou “inversão de controle”.

Licenciado em: CC-BY-SA com atribuição
Não afiliado a StackOverflow
scroll top