IDE: Eclipse ジュノ; コンパイラ: MinGW 4.6.2; プロジェクト: Win32
MdiChildWindowAとMdiChildWindowBの 2 つのやや異なる MDI 子ウィンドウを持つMainWindowがあります。3 番目の子ウィンドウであるSharedWindowは MDI ではありませんが、どちらの MDI 子ウィンドウでも使用できます。すべてが独自の C++ クラスにカプセル化されています。
SharedWindowの急増を避けるために、私はシングルトン設計の一部を借りました: SharedWindowMainWindowClass::GetSharedWindowInstance()
のインスタンスへのポインターを返し、まだ存在しない場合は作成します。 機能をバックアップするために含まれています。(これは、 SharedWindowがシングルトンになるのと同じくらい近いです。)MainWindow.h
SharedWindow* pSharedWindow
MainWindowがMdiChildWindowAとMdiChildWindowBをインスタンス化すると、それらのコンストラクターに渡され、クラス変数 (およびで定義) に保存されます。this
pMainWindow
MainWindow*
MdiChildWindowA.h
MdiChildWindowB.h
cout
MainWindowのofは MDI 子ウィンドウ コンストラクターの ofthis
に一致しますが、別の関数が呼び出すまでにが変更されました! 静的にすることで問題が解決したように見えますが、どのように変化しましたか?cout
pMainWindow
pMainWindow->GetSharedWindowInstance()
pMainWindow
pMainWindow
pMainWindow
同様に、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()
ここで、cout
showsthis
は0xdd13a0です。
MainWindowは への呼び出しで作成され、 inのRun(...)
インスタンスへのポインターを渡します。MainWindow
lpParam
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_CREATE
、cout
MdiChildWindowAおよび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_CREATE
MDI 子ウィンドウ プロシージャでは、まだ0xdd13a0cout
が含まれています。への他の唯一の参照は、静的にしない限り、どういうわけか0xdd1380になっています(おそらくパススルー中ですか?):m_pMainWindow
m_pMainWindow
WM_LBUTTONDBLCLICK
DefMDIChildProc(...)
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()
のこの偽のインスタンスに が存在するように見えますが、上記のコードでは!のアドレスです。MainWindow
MdiChildWindowA
(注: 私の命名規則は人を狂わせるので、危険性の低い名前でコードを再入力しました。タイプミスがないことを願っています。)
@brunocodutra、@Chris Hayes: まだコメントするのに十分なポイントがありませんが、あなたのアイデアに感謝します.