1

現在、C ++ / WTLプロジェクトをVisualStudio2005からVS2008に移植しています。プロジェクト構成の1つは、プリプロセッサシンボルUNIT_TESTを定義する単体テストビルドです。

WTLクラスをテストハーネスに取り込むために、CFakeWindowすべてのCWindowメソッドをスタブするクラスを作成しました。次に、stdafx.hファイルで、atlwin.h(CWindowクラスを定義する)のインポートのすぐ下でこれを行います。

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

私のウィンドウクラスは次のようになります。

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

これはVS2005でうまく機能します。問題は、VS 2008では、CFakeWindowクラスではなく、元のCWindowクラスのメソッドが呼び出されることです。CWindowもちろん、これにより、が散らばっているため、テストが失敗しATLASSERT(::IsWindow(m_hWnd))ます。

デバッガーでコードをステップ実行すると、CAboutDialogクラスがから継承していることがわかりCDialogImpl<CAboutDialog, CFakeWindow>ます。しかし、CAboutDialog(たとえばEndDialog(code))でメソッドを呼び出すと、CWindowメソッドが呼び出されます。

これはVS2008のバグですか、それとも私の条件付きテンプレート継承手法はVS 2005で許可されていたが、VS 2008では「修正」された忌まわしいものでしたか?回避策はありますか、それともWTLクラスを単体テストするために別の手法を検討する必要がありますか?この手法は、WTLライブラリをいじくり回すことなく、WTLクラスをテストハーネスに組み込むことができるため、非常に気に入っています。

編集:以下のConalへの応答に記載されているように、プリプロセッサの出力は、私のクラスがCFakeWindowから継承していることを示しています。

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

そして、上記のように、デバッガーでコードをステップ実行すると、CAboutDialogがCFakeWindowから継承したものとしてローカルウィンドウに表示されます。

編集2:Conalのアドバイスに従って、逆アセンブルを実行しました。コードはおそらくCFakeWindowメソッドを呼び出していますが、実際にはCWindowメソッドが呼び出されています。

        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) 

私はVC++2008デバッガーのバグにもっと傾倒し始めています。

4

6 に答える 6

4

これは、それを処理するより明確な方法かもしれません:

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

おそらく、再定義がプリコンパイル済みヘッダーを通過しない場合があります。もしそうなら、これはそのような問題をキャッチします。

于 2009-11-11T17:49:14.957 に答える
2

これはロングショットだと思いますが、プリコンパイルされたヘッダーがビルドに大混乱を引き起こしている可能性はありますか? プロジェクトでそれらをオフにして (オンになっている場合)、クリーン ビルドを実行して、より良い動作が得られるかどうかを確認してください。

于 2009-11-10T08:17:58.340 に答える
1

プリプロセッサの出力を見て、ハックが実際に自分の考えていることを実行していることを確認しましたか?プリプロセッサを使用してテンプレートライブラリの一部であるクラスの名前を変更すると、危険が伴います。また、CFakeWindowのすべてのメソッドの署名がCWindowと完全に一致することを確認してください。

VS2008はかなり前から存在しているので、他のすべての可能性を最初に排除するまで、コンパイラのバグを検討することはありません。

于 2009-10-25T08:47:31.210 に答える
1

次のようなものを試してください:

class CAboutDialog :
    public CDialogImpl<CAboutDialog, FAKE_CWindow_MACRO >

そうすれば、プリプロセッサを使用してシステム ヘッダー ファイルを書き換えようとするのをやめて、それを独自のコードに使用できます。

はい、コードを「リファクタリング」する必要があることはわかっていますが、それは検索と置換の仕事です。

あなたの現在の手法は、不当な仮定をしているため、ハックのようなものです.CWindowの一貫した定義に依存するATLからのヘッダーを#includeするソースファイルはないということです。これは、時間の経過とともにコードが変更されるため、安定しない可能性があります。

于 2009-11-11T17:39:39.320 に答える
1

次に、 stdafx.h ファイルでこれを行います

私の知る限り、 stdafx.h はデフォルトでプリコンパイル済みヘッダーです。したがって、マクロを定義しても、テンプレート引数としてUNIT_TESTまだあるプリコンパイル済みファイルには影響しません。CWindow

于 2009-11-11T17:46:08.240 に答える
1

ライブラリ シンボルが名前空間 ATL にあることがわかります。それはおそらくあなたのマクロのトリックを捨てていますか?

一般に、テンプレートのインスタンス化を完全に報告するデバッガーはありません。デバッグ ビルドであっても、非常に多くの奇妙な最適化が必要です。

于 2009-11-12T15:40:13.013 に答える