Posso usar o compilador C ++ do Visual Studio 2010 com o C ++ Runtime Library do Visual Studio 2008?

Eu tenho um aplicativo que precisa operar no Windows 2000. Eu também gostaria de usar o Visual Studio 2010 (principalmente por causa da alteração na definição da palavra auto chave auto ). No entanto, eu estou em um ligamento porque eu preciso que o aplicativo seja capaz de operar em sistemas operacionais mais antigos, a saber:

  • Windows 2000
  • Windows XP RTM
  • Windows XP SP1

A biblioteca de tempo de execução do Visual Studio 2010 depende da API EncodePointer / DecodePointer que foi introduzida no Windows XP SP2.

Se for possível usar a biblioteca de tempo de execução alternativa, este código de quebra que depende dos resources C ++ 0x adicionados no VS2010, como std::regex ?

A solução de Suma parecia bastante promissora, mas não funciona: os __imp__*@4 precisam ser pointers para funções, em vez das próprias funções. Infelizmente, eu não sei como fazer o Visual C ++ cuspir um ponteiro com esse tipo de geração de nome … (bem, __declspec(naked) combinado com __stdcall faz o truque, mas então eu não sei como emitir um ponteiro).

Se o uso de um assembler em tempo de construção estiver OK, a solução é bem trivial – monte o seguinte código com o FASM e faça um link com o arquivo de object produzido, e pronto – sem referências ao EncodePointer / DecodePointer no exe:

 use32 format ms coff section ".data" data public __imp__DecodePointer@4 __imp__DecodePointer@4 dd dummy public __imp__EncodePointer@4 __imp__EncodePointer@4 dd dummy section ".text" code dummy: mov eax, [esp+4] retn 4 

A solução mais simples é simplesmente definir o Toolset da plataforma em configurações de projeto no VS2010 a v900, que usará as bibliotecas e o compilador do Visual Studio 2008. Isso também significa que você perde os resources C ++ 0x como auto , mas, para ser honesto, trabalhar com isso com alguns typedef é provavelmente mais fácil do que construir sua própria versão do CRT ou outras soluções mais complicadas. Alternativamente, basta usar o VS2008! Eu não sei se existem outros resources C ++ 0x que são críticos para o seu aplicativo, você não mencionou – diferente de std::regex , que eu acho que ainda está no conjunto de ferramentas v900 sob o namespace do relatório técnico 1 ( std::tr1::regex ).

Apenas pela impressão que recebo, eu diria que a inconveniência de obter as bibliotecas do VS2010 para rodar no XP SP1 é maior do que a conveniência dos resources C ++ 0x, portanto, no geral, não valeria a pena.

Você não pode usar o CRT 2008, mas pode impedir que as novas funções DecodePointer / EncodePointer sejam vinculadas a partir do kernel. É muito fácil replace as novas funções por stubs.

Pode-se tentar seguir: Coloque o código como este em sua fonte main.cpp:

 extern "C" { void *__stdcall _imp__DecodePointer(void *x) {return x;} void *__stdcall _imp__EncodePointer(void *x) {return x;} }; 

O acima não funciona. Embora a ideia básica seja sólida, a execução precisa ser um pouco diferente. Conforme descrito por snemarch em comentário e outra resposta , __imp__ não pode ser a chamada de function, apenas o ponteiro para ela. Como parece não ser possível gerar o ponteiro diretamente pelo compilador, você precisa montar o seguinte código com MASM e vincular-se ao arquivo de object produzido.

 .model flat .data __imp__EncodePointer@4 dd dummy __imp__DecodePointer@4 dd dummy EXTERNDEF __imp__EncodePointer@4 : DWORD EXTERNDEF __imp__DecodePointer@4 : DWORD .code dummy proc mov eax, [esp+4] ret 4 dummy endp end 

Os símbolos de um projeto têm preferência contra quaisquer símbolos das bibliotecas. As bibliotecas DLL são vinculadas usando partes .lib, que contêm apenas “vetores” __imp__ que saltam para as funções reais. Ao replace __imp__ “vectors” você não toca na vinculação da DLL, substitui a parte .lib. Eu verifiquei que não há mais nenhuma dependência do exe em DecodePointer / EncodePointer.

fundo

A biblioteca vinculada estaticamente traz apenas a funcionalidade usada para o aplicativo. É possível descobrir qual function CRT específica traz a nova API usando a saída de progresso detalhada do vinculador:

 Found __imp__EncodePointer@4 Referenced in LIBCMT.lib(crtmboxw.obj) Referenced in LIBCMT.lib(invarg.obj) Referenced in LIBCMT.lib(handler.obj) Referenced in LIBCMT.lib(onexit.obj) Referenced in LIBCMT.lib(cmiscdat.obj) Referenced in LIBCMT.lib(tidtable.obj) Referenced in LIBCMT.lib(hooks.obj) Referenced in LIBCMT.lib(winsig.obj) Referenced in LIBCMT.lib(rand_s.obj) Found __imp__DecodePointer@4 // ... same list, only order differs ... 

Isso mostra que as novas APIs são usadas em alguns dos CRTs para fornecer mais segurança para algumas funções que são consideradas como vetores de ataque frequentes.

Com algum esforço, seria possível usar o LoadLibrary / GetProcAddress para fornecer a funcionalidade real que o SO oferece, mas não acho que isso realmente traria alguma coisa. As funções de tempo de execução que usam DecodePointer / EncodePointer realmente não precisam fornecer qualquer codificação, tudo o que precisam é que a codificação seja simétrica. Você realmente não precisa da segurança aprimorada (o runtime do VS 2008 também não o daria).

Espero que não haja outros obstáculos esperando por você – eu não tenho access ao sistema Win2k ou XP pré SP2, portanto, não posso tentar. Se houver algum sinalizador de header exe impedindo até mesmo tentar iniciar o exe em tais sistemas, eles devem ser fáceis de alterar.

Como o Visual Studio vem com suporte para MASM (veja propriedades do projeto -> Build Customizations …) a seguinte tradução do código de snemarch para MASM pode ser útil:

 .model flat .data __imp__EncodePointer@4 dd dummy __imp__DecodePointer@4 dd dummy EXTERNDEF __imp__EncodePointer@4 : DWORD EXTERNDEF __imp__DecodePointer@4 : DWORD .code dummy proc mov eax, [esp+4] ret 4 dummy endp end 

E lembre-se de configurar o Linker-> System-> Minimum Required Version para 5.0 (o padrão é 5.1) para rodar no Windows 2000.

A solução usual para esse problema é criar sua própria versão personalizada do CRT. Há instruções para isso aqui . Você só precisa editar o código para ignorar EncodePointer e DecodePointer . (Já deve haver um #define para isso.)

Existem outras duas pequenas coisas que você precisa fazer:

  • Vá para a configuração do Linker-> Additional Library Directories e defina C:\Microsoft Visual Studio 9.0\VC\lib como o primeiro caminho a ser pesquisado. (Estou supondo que você usou o diretório de instalação padrão, caso contrário, altere conforme apropriado.)
  • Altere a versão do subsistema, no header PE, para 5.00 (use o CFF Explorer Suite gratuito se você não tiver outra ferramenta à mão para isso).

Isso deve permitir que seu programa seja executado no Windows 2000, bem como em versões posteriores.

Opção 1 – crie uma versão modificada do tempo de execução de 2010 que redireciona as chamadas de API do problema para uma DLL que você fornece. Eu não sei quão fácil ou difícil isso seria – esperançosamente apenas um pequeno ajuste na tabela de símbolos, mas isso depende do formato do arquivo – e é muito provável que você encontre a cláusula de engenharia reversa da licença, é claro .

Opção 2 – Compare os símbolos exportados em duas versões diferentes das bibliotecas de tempo de execução. Se os símbolos são os mesmos, você tem boas chances de compatibilidade – embora não haja garantias. É até possível que os formatos de arquivo lib sejam diferentes.

Opção 3 – Verifique se você pode obter access a fonts em tempo de execução através do MSDN ou similar, especificamente para criar uma versão corrigida.

Opção 4 – Verifique se você pode usar o compilador 2010, mas um vinculador antigo, talvez configurado em suas soluções como uma etapa de compilation personalizada. Novamente, isso depende se os arquivos obj e lib têm o mesmo formato de arquivo – mas você pode gravar um pequeno utilitário para corrigir diferenças simples, como números de versão em um header. O vinculador mais antigo não deve ter problemas para vincular no tempo de execução mais antigo – assumindo que os objs do novo compilador são compatíveis com ele.

Opção 5 – crie DLLs em 2010 que não precisem de seu próprio tempo de execução, mas que sejam carregadas e hospedadas por um aplicativo criado usando o compilador mais antigo. Alcançar o requisito de “sem tempo de execução” para suas DLLs pode significar que muitas de suas bibliotecas devem ser construídas no aplicativo de hospedagem, é claro, e você pode precisar fornecer suas próprias interfaces (por meio do aplicativo host) para as funções da biblioteca que precisa trabalhar com – especialmente material de alocação de memory.

Opções que vale a pena conferir, mas tenho certeza de que você já pensou em todas elas – desculpe, não tenho idéia se alguma delas funcionará – ou se elas quase funcionarão, mas causarão problemas intermitentes.

Isso seria muito mais fácil se você tivesse permissão para usar uma DLL. Basicamente, escreva um EXE que não requer nenhuma function de tempo de execução C, usando a function linker / ENTRYPOINT. Depois de testar se os pré-requisitos básicos foram atendidos e relatar qualquer problema ao usuário por meio de apenas APIs fornecidas pelo Windows disponíveis em todos os sistemas operacionais de destino (por exemplo, MessageBox), chame LoadLibrary para iniciar a DLL que contém a maior parte de sua lógica . Essa DLL pode usar o tempo de execução VS2010 como de costume. Você pode até evitar a implantação de dois arquivos separados, descompactando a DLL de um recurso contido no seu principal .exe na boot. (Você pode fazer isso inteiramente na memory sem gravar o .DLL no disco, mas não se quiser aproveitar o carregador do Windows PE para corrigir todas as suas importações).

Crie um .LIB que implementa a funcionalidade ausente e vinculá-lo antes do KERNEL32.LIB.

Você precisará usar a opção de vinculador /NODEFAULTLIB:kernel32.lib para que você possa colocar seu w2kcompat.lib à frente do kernel32.lib.