Pergunta

Esta questão está relacionada com a "Como fazer dll consistente binários em versões VS? "

  • Temos aplicativos e DLLs construído com VC6 e uma nova aplicação construída com VC9. O VC9 app tem de utilização DLLs compilados com VC6, a maioria dos que são escritos em C e uma em C ++.
  • A C ++ lib é devido problemático Nome decoração / desconfiguração questões.
  • Compilação tudo com VC9 é atualmente não é uma opção, pois há Parece haver alguns efeitos colaterais. Resolver estes seriam bastante tempo consumindo.
  • Eu posso modificar a biblioteca C ++, no entanto, ele deve ser compilado com VC6.
  • lib O C ++ é essencialmente um OO-wrapper para outra biblioteca C. O VC9 app usa algumas funções estáticas, bem como alguns não-estático.

Enquanto as funções estáticas podem ser tratadas com algo como

// Header file
class DLL_API Foo
{
    int init();
}

extern "C"
{
    int DLL_API Foo_init();
}

// Implementation file
int Foo_init()
{
    return Foo::init();
}

não é tão fácil com os métodos não-estáticos.

Pelo que entendi, Chris Becke é sugestão de usar um cOM-like interface não vai me ajudar porque os nomes de membro interface ainda será decorado e, portanto, inacessível a partir de um binário criado com um compilador diferente. Am I ali?

Será que a única solução é escrever uma interface DLL C-estilo usando manipuladores aos objetos ou estou faltando alguma coisa? Nesse caso, eu acho, eu provavelmente teria menos esforço com diretamente usando o C-biblioteca embrulhado.

Foi útil?

Solução

nomes de membro interface irá não ser decorado - eles são apenas deslocamentos em uma vtable. Você pode definir uma interface (usando um struct C, em vez de um "interface" COM) em um arquivo de cabeçalho, assim:

struct IFoo {
    int Init() = 0;
};

Em seguida, você pode exportar uma função na DLL, sem deturpação:

class CFoo : public IFoo { /* ... */ };
extern "C" IFoo * __stdcall GetFoo() { return new CFoo(); }

Este belo trabalho vontade, desde que você está usando um compilador que gera vtables compatíveis. Microsoft C ++ gerou o mesmo formato vtable desde (pelo menos, eu acho) MSVC6.1 para DOS, onde o vtable é uma simples lista de ponteiros para funções (com thunking no caso de múltipla herança). GNU C ++ (se bem me lembro) gera vtables com ponteiros de função e compensações relativas. Estes não são compatíveis uns com os outros.

Outras dicas

O maior problema a considerar quando se usa um DLL compilado com um compilador diferente C ++ que o EXE que chama é a alocação de memória e objeto vida.

Estou assumindo que você pode passar a desconfiguração do nome (e convenção de chamada), o que não é difícil se você usar um compilador com mangling compatível (acho VC6 é amplamente compatível com VS2008), ou se você usar extern "C".

Onde você vai correr em problemas é quando você aloca algo usando new (ou malloc) da DLL, e depois devolver este para o chamador. delete do chamador (ou free) tentará liberar o objeto a partir de uma pilha diferente. Isso vai dar errado.

Você pode fazer uma coisa IFoo::Release de estilo COM, ou uma coisa MyDllFree(). Ambos, porque eles chamam de volta para a DLL, irá usar a aplicação correcta da delete (ou free()), então eles vão excluir o objeto correto.

Ou, você pode ter certeza que você use LocalAlloc (por exemplo), para que o EXE e DLL estão usando a mesma pilha.

Bem, eu acho é apenas multa. Eu não usaria primeira solução de Roger, que usa uma interface em apenas nome e, como ele menciona, pode ter problemas de compilador de manipulação de classes abstratas e métodos virtuais incompatíveis. Roger aponta para o caso COM consistente atraente em seu follow-on .

  1. O ponto de dor: Você precisa aprender a fazer pedidos de interface COM e lidar adequadamente com IUnknown, contando com pelo menos IUnknown: AddRef e IUnknown: Release. Se as implementações das interfaces pode suportar mais de uma interface ou se métodos também pode retornar interfaces, você também pode precisar de se sentir confortável com IUnknown:. QueryInterface

  2. Aqui está a idéia-chave. Todos os programas que usam a implementação da interface (mas não implementá-lo) usar um #include comum "* .h" arquivo que define a interface como um struct (C) ou a / C classe C ++ (VC ++) ou estrutura (não VC ++ mas C ++). O arquivo .h * adapta-se automaticamente de forma apropriada, dependendo se você está compilando um programa de linguagem C ou de um programa em linguagem C ++. Você não tem que saber sobre essa parte simplesmente usar o arquivo .h *. O que o arquivo * .h faz é definir a estrutura de interface ou tipo, digamos, IFoo, com as suas funções virtuais membros (e únicas funções, não haja visibilidade directa para membros de dados nesta abordagem).

  3. O arquivo de cabeçalho é construído para honrar o padrão COM binário de uma maneira que funciona para C e que funciona para C ++, independentemente do compilador C ++ que é usado. (O povo Java JNI figurou este para fora.) Isso significa que ele trabalha entre os módulos separadamente compilados de qualquer origem, desde que uma estrutura que consiste inteiramente de ponteiros função-entrada (a vtable) é mapeado para a memória da mesma por todos eles (então eles têm que ser tudo x86 de 32 bits, ou todos x64, por exemplo).

  4. Na DLL que implementa o a interface COM via uma classe de invólucro de algum tipo, você só precisa de um ponto de entrada da fábrica. Algo como um

    externo "C" HRESULT MkIFooImplementation (void ppv **);

que retorna um HRESULT (você vai precisar para aprender sobre os demais) e também irá retornar um pv * em um local que você fornecer para receber o ponteiro de interface IFoo. (Eu estou deslizando e há mais cuidadosos detalhes que você precisa aqui. Não confio no meu sintaxe) O estereótipo função real que você usa para isso também é declarada no arquivo .h *.

  1. O ponto é que a entrada da fábrica, que é sempre um extern undecorated "C" faz toda a criação classe wrapper necessário e, em seguida, oferece um ponteiro de interface IFoo para o local que você especificar. Isso significa que todo o gerenciamento de memória para a criação da classe, e todo o gerenciamento de memória para finalizá-lo, etc., vai acontecer na DLL onde você construir o invólucro. Este é o único lugar onde você tem que lidar com esses detalhes.

  2. Quando você obter um resultado OK da função de fábrica, ter sido emitido um ponteiro de interface e já foi reservado para você (há um IFoo implícito: operação Addref já realizado em nome do ponteiro de interface você foram entregues).

  3. Quando você é feito com a interface, você liberá-lo com uma chamada no IFoo: Método de lançamento da interface. É a implementação versão final (no caso de você fez cópias mais AddRef'd) que irá derrubar a classe e seu apoio interface na DLL fábrica. Isto é o que você recebe dependência correta em uma alocação stoorage dinâmica consistente e liberação por trás da interface, ou não o co DLLntaining a função fábrica utiliza as mesmas bibliotecas como o código de chamada.

  4. Você provavelmente deve implementar IUnknown: QueryInterface (como IFoo método: QueryInterface) também, mesmo que sempre falha. Se você quiser ser mais sofisticado com o uso do modelo de interface binária COM como você tem mais experiência, você pode aprender a fornecer implementações de QueryInterface completos.

Este é provavelmente muita informação, mas eu queria salientar que muitos dos problemas que estão enfrentando cerca de implementações heterogêneas de DLLs são resolvidos na definição do COM binário interface e mesmo se você não precisar de todos ele, o fato de que ele oferece soluções trabalhou é valioso. Na minha experiência, uma vez que você pegar o jeito de isso, você nunca vai esquecer o quão poderoso isso pode ser em C ++ e C ++ interoperabilidade situações.

Eu não esboçou os recursos que você pode precisar consultar para exemplos e que você tem que aprender a fim de fazer * .h e para realmente implementar wrappers-função fábrica das bibliotecas que você deseja compartilhar. Se você quiser ir mais fundo, gritar.

Há outras coisas que você precisa considerar também, como quais tempos de execução estão sendo usados ??pelas várias bibliotecas. Se nenhum objeto está sendo compartilhado Isso é bom, mas que parece bastante improvável à primeira vista.
As sugestões de Chris Becker são precisas - usando um real COM interface pode ajudá-lo a obter a compatibilidade binária que você precisa. Sua milhagem pode variar:)

Não é divertido, cara. você está em um monte de frustração, você provavelmente deve dar a este:

Será que a única solução seja para escrever um interface de DLL-estilo C utilizando manipuladores aos objetos ou estou perdendo alguma coisa? Nesse caso, eu acho, eu provavelmente teria menos esforço com diretamente usando o C-biblioteca embrulhado.

um olhar muito perto. boa sorte.

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