Pergunta

Eu estou no processo de portar a ++ / WTL projeto C a partir do Visual Studio 2005 para VS 2008 . uma das configurações de projeto é uma compilação de testes de unidade, que define o símbolo pré-processador UNIT_TEST.

A fim de obter as minhas aulas WTL no meu equipamento de teste, eu fiz uma classe CFakeWindow que as pontas de todos os métodos CWindow. Então no meu arquivo stdafx.h, eu faço isso logo abaixo da importação de atlwin.h (que define a classe CWindow):

#ifdef UNIT_TEST
#include "fakewindow.h"
#define CWindow CFakeWindow
#endif

As minhas classes de janela em seguida, parecido com este:

class CAboutDialog : 
    public CDialogImpl< CAboutDialog, CWindow > 
    , public CDialogResize< CAboutDialog >
{
// class definition omitted...
};

Isso funciona muito bem no VS 2005. O problema é que no VS 2008, os métodos da classe CWindow originais estão sendo chamados, em vez da classe CFakeWindow. Isto, obviamente, faz com que os testes para falhar, porque CWindow é polvilhado com ATLASSERT(::IsWindow(m_hWnd)).

Quando eu percorrer o código no depurador, vejo que a classe CAboutDialog está herdando de CDialogImpl<CAboutDialog, CFakeWindow>. No entanto, quando eu chamar um método em CAboutDialog (por exemplo EndDialog(code)), o método CWindow está sendo chamado.

Este é um bug no VS 2008, ou era minha técnica herança modelo condicional uma abominação que VS 2005 permitida, mas VS 2008 "fixo"? Existe uma solução alternativa, ou eu preciso considerar uma técnica diferente para aulas WTL-teste de unidade? Eu realmente gosto desta técnica, porque me permite obter aulas WTL em um equipamento de teste sem mucking com a biblioteca WTL.

Editar : Como observado na resposta a Conal, a seguir, mostra a saída de pré-processador que a minha classe é herdada de CFakeWindow:

class CAboutDialog :
    public CDialogImpl<CAboutDialog, CFakeWindow >
    , public CDialogResize< CAboutDialog >
    ...

E como dito acima, quando eu passo através do código no depurador, CAboutDialog é mostrado na janela locals como herança de CFakeWindow.

Editar 2 :. De acordo com o conselho de Conal, eu pisei através da desmontagem, eo código é supostamente chamando o método CFakeWindow, mas o método CWindow é o que é realmente chamado

        if ( wID == IDCANCEL ) 
00434898  movzx       edx,word ptr [ebp+8] 
0043489C  cmp         edx,2 
0043489F  jne         CAboutDialog::OnCloseCmd+90h (4348B0h) 
        {
            EndDialog( wID ) ;
004348A1  movzx       eax,word ptr [ebp+8] 
004348A5  push        eax  
004348A6  mov         ecx,dword ptr [ebp-10h] 
004348A9  call        ATL::CDialogImpl<CAboutDialog,ATL::CFakeWindow>::EndDialog (40D102h) 
        }
        else
004348AE  jmp         CAboutDialog::OnCloseCmd+9Ah (4348BAh) 
        {
            EndDialog(IDOK);
004348B0  push        1    
004348B2  mov         ecx,dword ptr [ebp-10h] 
004348B5  call        ATL::CDialogImpl<CAboutDialog,ATL::CFakeWindow>::EndDialog (40D102h) 

Estou começando a inclinar-se mais para um bug no VC ++ 2008 depurador.

Foi útil?

Solução

Esta pode ser uma maneira mais clara de lidar com ele:

#ifdef UNIT_TEST
#include "fakewindow.h"
#define TWindow CFakeWindow
#else
#define TWindow CWindow
#endif

Talvez há um caso em que a redefinição não está recebendo através dos cabeçalhos pré-compilados. Se assim for, isso vai pegar qualquer problema desse tipo.

Outras dicas

Eu acho que isso é um tiro longo, mas é possível que cabeçalhos pré-compilados estão jogando estragos com a sua construção? Experimente desligá-los em seu projeto (se eles estão on) e fazer uma compilação limpa para ver se você obter qualquer comportamento melhor.

Você olhou para a saída pré-processador para confirmar que o seu corte é na verdade fazendo o que você acha? Usando o pré-processador para mudar o nome de classes que fazem parte de um modelo de biblioteca é cheia de perigos. Além disso, verifique se a assinatura de cada método em sua CFakeWindow corresponde exatamente CWindow.

VS2008 tem sido em torno de um longo tempo agora, então eu não estaria considerando um erro compilador até que tenha eliminado primeiro todas as outras possibilidades.

Tente algo como:

class CAboutDialog :
    public CDialogImpl<CAboutDialog, FAKE_CWindow_MACRO >

Dessa forma, você pode parar de tentar usar o pré-processador para reescrever os arquivos de cabeçalho do sistema, e usá-lo para o seu próprio código.

Sim, eu sei que você tem que "refatorar" seu código, mas é uma pesquisa e substituição de trabalho.

Sua técnica atual é algo de um hack porque faz um pressuposto injustificado: que nenhum arquivo de origem será #include qualquer cabeçalho da ATL que se baseia em uma definição consistente de CWindow. Esta não é susceptível de ser estável como código muda ao longo do tempo.

Em seguida, no meu arquivo stdafx.h, eu faço isso

AFAIK, stdafx.h é um cabeçalho pré-compilado por padrão. Então, quando você definir UNIT_TEST macro, ele não afeta arquivo, que ainda tem CWindow como argumento template pré-compilados.

Eu vejo os símbolos da biblioteca estão no ATL namespace. É que talvez jogando fora de sua malandragem macro?

Em geral, eu não iria contar com qualquer depurador para instâncias do modelo de relatório perfeitamente. Muitas otimizações estranhas são obrigados a acontecer mesmo em compilações de depuração.

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