0

IDE: Eclipse ジュノ; コンパイラ: MinGW 4.6.2; プロジェクト: Win32

MdiChildWindowAMdiChildWindowBの 2 つのやや異なる MDI 子ウィンドウを持つMainWindowがあります。3 番目の子ウィンドウであるSharedWindowは MDI ではありませんが、どちらの MDI 子ウィンドウでも使用できます。すべてが独自の C++ クラスにカプセル化されています。

SharedWindowの急増を避けるために、私はシングルトン設計の一部を借りました: SharedWindowMainWindowClass::GetSharedWindowInstance()のインスタンスへのポインターを返し、まだ存在しない場合は作成します。 機能をバックアップするために含まれています。(これは、 SharedWindowがシングルトンになるのと同じくらい近いです。)MainWindow.hSharedWindow* pSharedWindow

MainWindowがMdiChildWindowAMdiChildWindowBをインスタンス化すると、それらのコンストラクターに渡さ、クラス変数 (およびで定義) に保存されます。thispMainWindowMainWindow*MdiChildWindowA.hMdiChildWindowB.h

coutMainWindowのofは MDI 子ウィンドウ コンストラクターの ofthisに一致しますが、別の関数が呼び出すまでにが変更されました! 静的にすることで問題が解決したように見えますが、どのように変化しましたか?coutpMainWindowpMainWindow->GetSharedWindowInstance()pMainWindowpMainWindowpMainWindow

同様に、HMODULEと のLPPICTURE変数が で静的であるSharedWindow.hか、 の関数間で値を忘れてしまうことがわかりましたSharedWindow.cppポインター型は、クラス変数としての永続性から何らかの形で免除されていますか? staticクラスのすべてのインスタンスで1つの値を確保することを意図している と思いました。

編集 2013-Sep-04:
以下は私のものですApplication.cpp(大部分はチュートリアルからコピーされたものです)。MainWindowインスタンスがヒープ上に作成され、終了するまで持続すると思っていました。

#include "MainWindow.h"

int WINAPI WinMain( HINSTANCE hInstance, HINSTANCE hPrev, LPSTR lpCmdLine, int nCmdShow )
{   MSG  msg;
    HWND hMdiClientWindow;

    MainWindow *winMain = new MainWindow( hInstance );
    if( !winMain->Run( nCmdShow ) )
    {   delete winMain;
        return 1;
    }

    hMdiClientWindow = winMain->GetMdiClientWindow();

    while( GetMessage( &msg, NULL, 0, 0 ) )
    {   if( ! TranslateMDISysAccel( hMdiClientWindow, &msg ) )
        {   TranslateMessage( &msg );
            DispatchMessage ( &msg );
        }
    }

    delete winMain;

    return msg.wParam;
}

new MainWindow(...)MainWindow::MainWindow()ここで、coutshowsthisは0xdd13a0です

MainWindowは への呼び出しで作成され、 inのRun(...)インスタンスへのポインターを渡します。MainWindowlpParam

bool MainWindow::Run( int nCmdShow )
{   ...
    hMainWindow = CreateWindowEx( ..., this );
    ...
}

ウィンドウ プロシージャでは、ポインターはMainWindowのインスタンス データに保存されます。

LRESULT CALLBACK MainWindow::MainWindowProcedure( HWND hMainWindow, UINT Msg, WPARAM wParam, LPARAM lParam )
{   MainWindow* pThis;

    if( Msg == WM_NCCREATE )
    {   CREATESTRUCT* pCreateStruct = (CREATESTRUCT*) lParam;
        pThis = (MainWindow*) pCreateStruct->lpCreateParams;
        SetWindowLongPtr( hMainWindow, GWL_USERDATA, (LONG) pThis );
    } else
    {   pThis = (MainWindow*) GetWindowLongPtr( hMainWindow, GWL_USERDATA );
    }

ではWM_CREATEcoutMdiChildWindowAおよびMdiChildWindowBのコンストラクターに渡されると、 0xdd13a0pThis表示されます。

switch( Msg )
{   ...
    case WM_CREATE:
    {   unique_ptr<MdiChildWindowA> upMdiChildWindowA;
        unique_ptr<MdiChildWindowB> upMdiChildWindowB;
        ...
        up_MdiChildWindowA = unique_ptr<MdiChildWindowA>( new MdiChildWindowA( m_hInstance, pThis, [window dimensions] ) );
        up_MdiChildWindowB = unique_ptr<MdiChildWindowB>( new MdiChildWindowB( m_hInstance, pThis, [window dimensions] ) );

MDI 子ウィンドウのコンストラクターはMainWindow、パラメーターのポインターをpMainWindowクラス変数にコピーし、両方に0xdd13a0m_pMainWindowが含まれていることを示します。cout

MdiChildWindowA::MdiChildWindowA( HINSTANCE hInstance, MainWindow* pMainWindow, ... )
{   m_pMainWindow = pMainWindow;
    ....
}

WM_CREATEMDI 子ウィンドウ プロシージャでは、まだ0xdd13a0coutが含まれています。への他の唯一の参照は、静的にしない限り、どういうわけか0xdd1380になっています(おそらくパススルー中ですか?):m_pMainWindowm_pMainWindowWM_LBUTTONDBLCLICKDefMDIChildProc(...)

MdiChildWindowA::MdiChildWindowProcedure( ... )
{   ...
    switch( ... )
    {   ...
        case WM_LBUTTONDBLCLICK:
        {   SharedWindow* pSharedWindow;
            ...
            pSharedWindow = pThis->m_pMainWindow->GetInstanceOfSharedWindow();  // pThis points to this instance of MdiChildWindowA. cout confirms its value hasn't changed.

m_pMainWindowが間違った場所を指しているため、関数が 経由で呼び出されるとプログラムがクラッシュしSharedWindowますpSharedWindow。ただし、アドレスが返されるため、GetInstanceOfSharedWindow()のこの偽のインスタンスに が存在するように見えますが、上記のコードでは!のアドレスです。MainWindowMdiChildWindowA

(注: 私の命名規則は人を狂わせるので、危険性の低い名前でコードを再入力しました。タイプミスがないことを願っています。)

@brunocodutra、@Chris Hayes: まだコメントするのに十分なポイントがありませんが、あなたのアイデアに感謝します.

4

1 に答える 1

0

関連する完全なコードがないとわかりにくいですが、 MainWindowの割り当てが解除されていると思います。さらに、アドレスが変更される原因は関数呼び出し (スタックを変更する) であるため、 MainWindowは元々ヒープではなくスタックに格納されていると思います。

私のアドバイス: MainWindowまたはMdiChildWindowAMdiChildWindowB ( pMainWindowの変更がわからない) のいずれかがローカル変数であるかどうかを確認し、そうであればコードを変更して、ヒープに割り当てられるようにします。つまり、キーワードnewを使用して動的に割り当てられます。

2 番目の質問に答えると、ポインタは他のどの型とも異なる扱いはされません。本質的には整数と非常によく似ていますが、その内容はすぐにメモリ アドレスとして解釈されます。

于 2013-09-04T02:34:47.570 に答える