パソコンでプログラミングしよう ウィンドウズC++プログラミング環境の構築
1.7.5.3(3)
本サイトは移転しました。旧アドレスからのリダイレクトは2025年03月31日(月)まで有効です。
🛈
ソースコード(wxWidgetsとシステムシャットダウン)

ウィンドウズシャットダウン時のwxWidgetsアプリケーション挙動に関与する部分のソースコードを示す。

本記事はwxWidgetsとシステムシャットダウン(以下、解説記事)で調査したソースコードをまとめる。解説記事はwxAppクラス、wxEventLoopクラス、wxTopLevelWindowクラスを説明するが、記述を簡潔とするため大きく省略し各メンバ関数はそれぞれのクラスで定義されているとした。実際はより複雑でメンバ関数の多くは基底クラスで定義されていて、また仮想メンバ関数のオーバーライドが基底メンバ関数をコール場合もある。本記事はより正確な参照に供すべく各メンバ関数のソースコードを記載するが、解説記事以上の内容は加えない。用語は解説記事に準ずる。

ダウンロードリンク

最新バージョンと過去バージョンは以下リンクからダウンロードできる。本記事調査はバージョン3.2.2.1ソースコードを用いた。

グローバル定義

wxEntry関数

wxEntry関数

[src\msw\main.cpp:169]

int wxEntry(int& argc, wxChar **argv)
{
DisableAutomaticSETranslator();
wxSEH_TRY
{
return wxEntryReal(argc, argv);
}
wxSEH_HANDLE(-1)
}

wxEntryReal関数

wxInitializerクラス[include\wx\init.h:81]はアプリケーションの初期化/終了処理を行うRAIIオブジェクトである。wxInitializerはコンストラクタからいくつかの関数を経由して最終的にはwxEntryStart関数[src\common\init.cpp:290]でライブラリの初期化行い、デストラクタからいくつかの関数を経由して最終的にはwxEntryCleanup関数(実際はwxEntryCleanupReal関数)[src\common\init.cpp:444]でライブラリの終了処理を行う。初期化はwxAppConsole派生のインスタンスであるwxAppConsoleBase::ms_appInstanceスタティックメンバ変数も構築し、終了処理はそれを解体する。

[src\common\int.cpp:475]

int wxEntryReal(int& argc, wxChar **argv)
{
// library initialization
wxInitializer initializer(argc, argv);
if ( !initializer.IsOk() )
{
#if wxUSE_LOG
// flush any log messages explaining why we failed
delete wxLog::SetActiveTarget(NULL);
#endif
return -1;
}
wxTRY
{
// app initialization
if ( !wxTheApp->CallOnInit() )
{
// don't call OnExit() if OnInit() failed
return -1;
}
// ensure that OnExit() is called if OnInit() had succeeded
class CallOnExit
{
public:
~CallOnExit() { wxTheApp->OnExit(); }
} callOnExit;
WX_SUPPRESS_UNUSED_WARN(callOnExit);
// app execution
return wxTheApp->OnRun();
}
wxCATCH_ALL( wxTheApp->OnUnhandledException(); return -1; )
}

wxTheAppインスタンス

wxTheAppインスタンスの実装はwxAppConsoleBase::ms_appInstanceスタティックメンバ変数を返すマクロ定義による。

[include\wx\app.h:785]

#define wxTheApp static_cast<wxApp*>(wxApp::GetInstance())

[include\wx\app.h:73]

class WXDLLIMPEXP_BASE wxAppConsoleBase : public wxEvtHandler,
public wxEventFilter
{
public:
...
static wxAppConsole *GetInstance() { return ms_appInstance; }
static void SetInstance(wxAppConsole *app) { ms_appInstance = app; }
...
protected:
...
static wxAppConsole *ms_appInstance;
...
};

グローバル変数

解説記事でグローバル変数wxTopLevelWindow/wxPendingDeleteの型は説明目的のソースコード上に実在しない仮想クラステンプレートwxList<T>にwxWindow/wxObjectをテンプレート実引数に与えた特殊化とした。解説記事はstd::list<T*>との互換インターフェースで説明したがソースコードは非互換インターフェースが混在する。それぞれ実際のクラスはマクロ展開を用いて定義したwxWindowList/wxListで、wxList<T>特殊化で表せばwxList<wxWindow>/wxList<wxObject>である。ソースコード上に実在するwxListクラスと実在しないwxList<T>仮想クラステンプレートを混同しないように。

wxTopLevelWindows変数

[src\common\wincmn.cpp:88]

WXDLLIMPEXP_DATA_CORE(wxWindowList) wxTopLevelWindows;

wxWindowListクラスは仮想クラステンプレート特殊化であるwxList<wxWindow>で、クラス定義とメンバ関数定義はマクロ展開による。

[include\wx\window.h:153]

WX_DECLARE_LIST_3(wxWindow, wxWindowBase, wxWindowList, wxWindowListNode, class WXDLLIMPEXP_CORE);

[src\common\wincmn.cpp:3283]

WX_DEFINE_LIST(wxWindowList)

wxPendingDelete変数

[src\common\appbase.cpp:150]

WXDLLIMPEXP_DATA_BASE(wxList) wxPendingDelete;

wxListクラス[src\include\wx\list.h:1167]はwxObjectListクラスからの派生だが解説記事の範囲ではwxObjectListと同じと考えて良い。wxObjectListクラスは仮想クラステンプレート特殊化であるwxList<wxObject>で、クラス定義とメンバ関数定義はマクロ展開による。

[include\wx\list.h:1164]

WX_DECLARE_LIST_2(wxObject, wxObjectList, wxObjectListNode,
class WXDLLIMPEXP_BASE);

[src\common\list.cpp:736]

WX_DEFINE_LIST(wxObjectList)

wxAppクラス

イベントテーブル

[src\msw\app.cpp:624]

wxBEGIN_EVENT_TABLE(wxApp, wxEvtHandler)
EVT_IDLE(wxApp::OnIdle)
EVT_END_SESSION(wxApp::OnEndSession)
EVT_QUERY_END_SESSION(wxApp::OnQueryEndSession)
wxEND_EVENT_TABLE()

OnRunメンバ関数

wxAppBase::OnRunメンバ関数

[src\common\appcmn.cpp:324]

int wxAppBase::OnRun()
{
// see the comment in ctor: if the initial value hasn't been changed, use
// the default Yes from now on
if ( m_exitOnFrameDelete == Later )
{
m_exitOnFrameDelete = Yes;
}
//else: it has been changed, assume the user knows what he is doing
return wxAppConsole::OnRun();
}

wxAppConsoleBase::OnRunメンバ関数

[src\common\appbase.cpp:301]

int wxAppConsoleBase::OnRun()
{
return MainLoop();
}

wxAppConsoleBase::MainLoopメンバ関数

[src\common\appbase.cpp:374]

int wxAppConsoleBase::MainLoop()
{
wxEventLoopBaseTiedPtr mainLoop(&m_mainLoop, CreateMainLoop());
if (wxTheApp)
wxTheApp->OnLaunched();
return m_mainLoop ? m_mainLoop->Run() : -1;
}

OnExitメンバ関数

wxAppBase::OnExitメンバ関数

[src\common\appcmn.cpp:337]

int wxAppBase::OnExit()
{
#ifdef __WXUNIVERSAL__
delete wxTheme::Set(NULL);
#endif // __WXUNIVERSAL__
return wxAppConsole::OnExit();
}

wxAppConsoleBase::OnExitメンバ関数

[src\common\appbase:310]

int wxAppConsoleBase::OnExit()
{
// Delete all pending objects first, they might use wxConfig to save their
// state during their destruction.
DeletePendingObjects();
#if wxUSE_CONFIG
// Ensure we won't create it on demand any more if we hadn't done it yet.
wxConfigBase::DontCreateOnDemand();
#endif // wxUSE_CONFIG
return 0;
}

wxAppConsoleBase::DeletePendingObjectsメンバ関数

[src\common\appbase.cpp:628]

void wxAppConsoleBase::DeletePendingObjects()
{
wxList::compatibility_iterator node = wxPendingDelete.GetFirst();
while (node)
{
wxObject *obj = node->GetData();
// remove it from the list first so that if we get back here somehow
// during the object deletion (e.g. wxYield called from its dtor) we
// wouldn't try to delete it the second time
if ( wxPendingDelete.Member(obj) )
wxPendingDelete.Erase(node);
delete obj;
// Deleting one object may have deleted other pending
// objects, so start from beginning of list again.
node = wxPendingDelete.GetFirst();
}
}

ExitMainLoopメンバ関数

wxAppConsoleBase::ExitMainLoopメンバ関数

[src\common\appbase.cpp:384]

void wxAppConsoleBase::ExitMainLoop()
{
// we should exit from the main event loop, not just any currently active
// (e.g. modal dialog) event loop
if ( m_mainLoop && m_mainLoop->IsRunning() )
{
m_mainLoop->Exit(0);
}
}

ProcessIdleメンバ関数

wxAppConsoleBase::ProcessIdleメンバ関数

[src\common\appbase.cpp:430]

bool wxAppConsoleBase::ProcessIdle()
{
// synthesize an idle event and check if more of them are needed
wxIdleEvent event;
event.SetEventObject(this);
ProcessEvent(event);
#if wxUSE_LOG
// flush the logged messages if any (do this after processing the events
// which could have logged new messages)
wxLog::FlushActive();
#endif
// Garbage collect all objects previously scheduled for destruction.
DeletePendingObjects();
return event.MoreRequested();
}

WakeUpIdleメンバ関数

wxApp::WakeUpIdleメンバ関数

[src\msw\app.cpp:805]

void wxApp::WakeUpIdle()
{
wxEventLoopBase * const evtLoop = wxEventLoop::GetActive();
if ( !evtLoop )
{
// We can't wake up the event loop if there is none and there is just
// no need to do anything in this case, any pending events will be
// handled when the event loop starts.
return;
}
evtLoop->WakeUp();
}

GetTopWindowメンバ関数

解体遅延されるTLWを除く処理はバージョン3.1.1で追加された(※1)。

wxAppBase::GetTopWindowメンバ関数

[src\common\appcmn.cpp:169]

wxWindow* wxAppBase::GetTopWindow() const
{
wxWindow* window = m_topWindow;
// If there is no top window or it is about to be destroyed,
// we need to search for the first TLW which is not pending delete
if ( !window || wxPendingDelete.Member(window) )
{
window = NULL;
wxWindowList::compatibility_iterator node = wxTopLevelWindows.GetFirst();
while ( node )
{
wxWindow* win = node->GetData();
if ( !wxPendingDelete.Member(win) )
{
window = win;
break;
}
node = node->GetNext();
}
}
return window;
}

OnQueryEndSessionメンバ関数

wxApp::OnQueryEndSessionメンバ関数

[src\msw\app.cpp:864]

void wxApp::OnQueryEndSession(wxCloseEvent& event)
{
if (GetTopWindow())
{
if (!GetTopWindow()->Close(!event.CanVeto()))
event.Veto(true);
}
}

OnEndSessionメンバ関数

C言語標準ライブラリexit関数でアプリケーションを終了してwxEntryReal関数に戻らないため、wxEntryCleanup関数をexit前にコールする。DeleteAllTLWsメンバ関数によるTLW全解体はバージョン3.2.1で加えられた(※3)。

wxApp::OnEndSessionメンバ関数

[src\msw\app.cpp:833]

void wxApp::OnEndSession(wxCloseEvent& WXUNUSED(event))
{
// Windows will terminate the process soon after we return from
// WM_ENDSESSION handler or when we delete our last window, so make sure we
// at least execute our cleanup code before
// prevent the window from being destroyed when the corresponding wxTLW is
// destroyed: this will result in a leak of a HWND, of course, but who
// cares when the process is being killed anyhow
if ( !wxTopLevelWindows.empty() )
wxTopLevelWindows[0]->SetHWND(0);
// Destroy all the remaining TLWs before calling OnExit() to have the same
// sequence of events in this case as in case of the normal shutdown,
// otherwise we could have many problems due to wxApp being already
// destroyed when window cleanup code (in close event handlers or dtor) is
// executed.
DeleteAllTLWs();
const int rc = OnExit();
wxEntryCleanup();
// calling exit() instead of ExitProcess() or not doing anything at all and
// being killed by Windows has the advantage of executing the dtors of
// global objects
exit(rc);
}

wxAppBase::DeleteAllTLWsメンバ関数

[src\common\appcmn.cpp:130]

void wxAppBase::DeleteAllTLWs()
{
// TLWs remove themselves from wxTopLevelWindows when destroyed, so iterate
// until none are left.
while ( !wxTopLevelWindows.empty() )
{
// do not use Destroy() here as it only puts the TLW in pending list
// but we want to delete them now
delete wxTopLevelWindows.GetFirst()->GetData();
}
}

wxEventLoopクラス

wxEventLoopコンストラクタ

wxMSWEventLoopBase::wxMSWEventLoopBaseコンストラクタ

[src\msw\evtloopconsole.cpp:38]

wxMSWEventLoopBase::wxMSWEventLoopBase()
{
m_shouldExit = false;
m_exitcode = 0;
// Create initially not signalled auto-reset event object.
m_heventWake = ::CreateEvent(NULL, FALSE, FALSE, NULL);
if ( !m_heventWake )
wxLogLastError(wxS("CreateEvent(wake)"));
}

~wxEventLoopデストラクタ

wxMSWEventLoopBase::~wxMSWEventLoopBaseデストラクタ

[src\msw\evtloopconsole.cpp:49]

wxMSWEventLoopBase::~wxMSWEventLoopBase()
{
if ( m_heventWake && !::CloseHandle(m_heventWake) )
wxLogLastError(wxS("CloseHandle(wake)"));
}

Runメンバ関数

関数コールは深いがDoRunメンバ関数のメッセージループとwxConsoleEventLoop::Dispatchメンバ関数における処理に要約できる。

wxEventLoopBase::Runメンバ関数

[src\common\evtloopcmn.cpp:68]

int wxEventLoopBase::Run()
{
// event loops are not recursive, you need to create another loop!
wxCHECK_MSG( !IsInsideRun(), -1, wxT("can't reenter a message loop") );
// ProcessIdle() and ProcessEvents() below may throw so the code here should
// be exception-safe, hence we must use local objects for all actions we
// should undo
wxEventLoopActivator activate(this);
// We might be called again, after a previous call to ScheduleExit(), so
// reset this flag.
m_shouldExit = false;
// Set this variable to true for the duration of this method.
m_isInsideRun = true;
wxON_BLOCK_EXIT_SET(m_isInsideRun, false);
// Finally really run the loop.
return DoRun();
}

wxEventLoopManual::DoRunメンバ関数

メッセージループを実装するが解説記事で省略した遅延イベント(wxEvtHandler::QueueEventメンバ関数[src\common\event.cpp:1285]で登録されて次のメッセージループまで処理遅延されるイベント)処理を含む。最外郭forループは例外処理で、次レベルのforループが遅延イベント処理を含むメッセージループであるが、それでも遅延イベントを残して抜ける場合があるので遅延イベント処理のみ行うforループが後続する。メッセージループ内のwhileループは終了フラグ(m_shouldExitメンバ変数)が立っておらずかつ遅延イベントが残っていなければ、アイドル処理としてwxTheApp->ProcessIdleコールがfalseを返すまで繰り返す。イベント処理は遅延イベントを含めてwxEventLoopManual::ProcessEventsコールが行うが、これがfalseを返す(WM_QUITメッセージがポストされた)かm_shouldExitフラグが立てばメッセージループは終了する。

[src\msw\evtloopconsole.cpp:246]

int wxEventLoopManual::DoRun()
{
// we must ensure that OnExit() is called even if an exception is thrown
// from inside ProcessEvents() but we must call it from Exit() in normal
// situations because it is supposed to be called synchronously,
// wxModalEventLoop depends on this (so we can't just use ON_BLOCK_EXIT or
// something similar here)
#if wxUSE_EXCEPTIONS
for ( ;; )
{
try
{
#endif // wxUSE_EXCEPTIONS
// this is the event loop itself
for ( ;; )
{
// give them the possibility to do whatever they want
OnNextIteration();
// generate and process idle events for as long as we don't
// have anything else to do, but stop doing this if Exit() is
// called by one of the idle handlers
//
// note that Pending() only checks for pending events from the
// underlying toolkit, but not our own pending events added by
// QueueEvent(), so we need to call HasPendingEvents() to check
// for them too
while ( !m_shouldExit
&& !Pending()
&& !(wxTheApp && wxTheApp->HasPendingEvents())
&& ProcessIdle() )
;
// if Exit() was called, don't dispatch any more events here
if ( m_shouldExit )
break;
// a message came or no more idle processing to do, dispatch
// all the pending events and call Dispatch() to wait for the
// next message
if ( !ProcessEvents() || m_shouldExit )
break;
}
// Process any still pending events.
for ( ;; )
{
bool hasMoreEvents = false;
// We always dispatch events pending at wx level: it may be
// important to do it before the loop exits and e.g. the modal
// dialog possibly referenced by these events handlers is
// destroyed. It also shouldn't result in the problems
// described below for the native events and while there is
// still a risk of never existing the loop due to an endless
// stream of events generated from the user-defined event
// handlers, we consider that well-behaved programs shouldn't
// do this -- and if they do, it's better to keep running the
// loop than crashing after leaving it.
if ( wxTheApp && wxTheApp->HasPendingEvents() )
{
wxTheApp->ProcessPendingEvents();
hasMoreEvents = true;
}
// For the underlying toolkit events, we only handle them when
// exiting the outermost event loop but not when exiting nested
// loops. This is required at least under MSW where, in case of
// a nested modal event loop, the modality has already been
// undone as Exit() had been already called, so all UI elements
// are re-enabled and if we dispatched events from them here,
// we could end up reentering the same event handler that had
// shown the modal dialog in the first place and showing the
// dialog second time before its first instance was destroyed,
// resulting in a lot of fun.
//
// Also, unlike wx events above, it should be fine to dispatch
// the native events from the outer event loop, as any events
// generated from outside the dialog itself (necessarily, as
// the dialog is already hidden and about to be destroyed)
// shouldn't reference the dialog. Which is one of the reasons
// we still dispatch them in the outermost event loop, to
// ensure they're still processed. Another reason is that if we
// do have an endless stream of native events, e.g. because we
// have a timer with a too short interval, it's arguably better
// to keep handling them instead of exiting.
if ( gs_eventLoopCount == 1 )
{
if ( Pending() )
{
Dispatch();
hasMoreEvents = true;
}
}
if ( !hasMoreEvents )
break;
}
#if wxUSE_EXCEPTIONS
// exit the outer loop as well
break;
}
catch ( ... )
{
try
{
if ( !wxTheApp || !wxTheApp->OnExceptionInMainLoop() )
{
OnExit();
break;
}
//else: continue running the event loop
}
catch ( ... )
{
// OnException() thrown, possibly rethrowing the same
// exception again: very good, but we still need OnExit() to
// be called
OnExit();
throw;
}
}
}
#endif // wxUSE_EXCEPTIONS
return m_exitcode;
}

wxEventLoopBase::ProcessIdleメンバ関数

[src\common\evtloopcmn.cpp:102]

bool wxEventLoopBase::ProcessIdle()
{
return wxTheApp && wxTheApp->ProcessIdle();
}

wxEventLoopManual::ProcessEventsメンバ関数

遅延イベント処理はwxAppConsoleBase::ProcessPendingEventsメンバ関数[src\common\appbase.cpp:546]に委ね、それ以外はwxConsoleEventLoop::Dispatchメンバ関数に委ねる。

[src\common\evtloopcmn.cpp:214]

bool wxEventLoopManual::ProcessEvents()
{
// process pending wx events first as they correspond to low-level events
// which happened before, i.e. typically pending events were queued by a
// previous call to Dispatch() and if we didn't process them now the next
// call to it might enqueue them again (as happens with e.g. socket events
// which would be generated as long as there is input available on socket
// and this input is only removed from it when pending event handlers are
// executed)
if ( wxTheApp )
{
wxTheApp->ProcessPendingEvents();
// One of the pending event handlers could have decided to exit the
// loop so check for the flag before trying to dispatch more events
// (which could block indefinitely if no more are coming).
if ( m_shouldExit )
return false;
}
const bool res = Dispatch();
#if wxUSE_EXCEPTIONS
// Rethrow any exceptions which could have been produced by the handlers
// ran by Dispatch().
if ( wxTheApp )
wxTheApp->RethrowStoredException();
#endif // wxUSE_EXCEPTIONS
return res;
}

wxConsoleEventLoop::Dispatchメンバ関数

メッセージウェイトはwxMSWEventLoopBase::GetNextMessageメンバ関数による。

[src\msw\evtloopconsole.cpp:157]

bool wxConsoleEventLoop::Dispatch()
{
MSG msg;
if ( !GetNextMessage(&msg) )
return false;
ProcessMessage(&msg);
return !m_shouldExit;
}

wxMSWEventLoopBase::GetNextMessageメンバ関数

[src\msw\evtloopconsole.cpp:97]

bool wxMSWEventLoopBase::GetNextMessage(WXMSG* msg)
{
return GetNextMessageTimeout(msg, INFINITE) == TRUE;
}

wxMSWEventLoopBase::GetNextMessageTimeoutメンバ関数

[src\msw\evtloopconsole.cpp:102]

int wxMSWEventLoopBase::GetNextMessageTimeout(WXMSG *msg, unsigned long timeout)
{
// MsgWaitForMultipleObjects() won't notice any input which was already
// examined (e.g. using PeekMessage()) but not yet removed from the queue
// so we need to remove any immediately messages manually
while ( !::PeekMessage(msg, 0, 0, 0, PM_REMOVE) )
{
DWORD rc = ::MsgWaitForMultipleObjects
(
1, &m_heventWake,
FALSE,
timeout,
QS_ALLINPUT | QS_ALLPOSTMESSAGE
);
switch ( rc )
{
default:
wxLogDebug("unexpected MsgWaitForMultipleObjects() return "
"value %lu", rc);
wxFALLTHROUGH;
case WAIT_TIMEOUT:
return -1;
case WAIT_OBJECT_0:
// We were woken up by a background thread, which means there
// is no actual input message available, but we should still
// return to the event loop, so pretend there was WM_NULL in
// the queue.
wxZeroMemory(*msg);
return TRUE;
case WAIT_OBJECT_0 + 1:
// Some message is supposed to be available, but spurious
// wake ups are also possible, so just return to the loop:
// either we'll get the message or start waiting again.
break;
}
}
return msg->message != WM_QUIT;
}

WakeUpメンバ関数

wxMSWEventLoopBase::WakeUpメンバ関数

[src\msw\evtloopconsole.cpp:65]

void wxMSWEventLoopBase::WakeUp()
{
if ( !::SetEvent(m_heventWake) )
wxLogLastError(wxS("SetEvent(wake)"));
}

Exitメンバ関数

Exitメンバ関数はDispatchメンバ関数によるメッセージ処理からコールされるので、リターンはDispatchへ戻る。m_exitcodeフラグを立ててウェイクアップする事でメッセージループを終了する。

wxEventLoopBase::Exitメンバ関数

[src\common\evtloopcmn.cpp:90]

void wxEventLoopBase::Exit(int rc)
{
wxCHECK_RET( IsRunning(), wxS("Use ScheduleExit() on not running loop") );
ScheduleExit(rc);
}

wxEventLoopManual::ScheduleExitメンバ関数

[src\common\evtloopcmn.cpp:376]

void wxEventLoopManual::ScheduleExit(int rc)
{
wxCHECK_RET( IsInsideRun(), wxT("can't call ScheduleExit() if not running") );
m_exitcode = rc;
m_shouldExit = true;
OnExit();
// all we have to do to exit from the loop is to (maybe) wake it up so that
// it can notice that Exit() had been called
//
// in particular, do *not* use here calls such as PostQuitMessage() (under
// MSW) which terminate the current event loop here because we're not sure
// that it is going to be processed by the correct event loop: it would be
// possible that another one is started and terminated by mistake if we do
// this
WakeUp();
}

wxTopLevelWindowクラス

wxTopLevelWindowMSWとwxWindowMSWは__WXMSW__定義かつ__WXUNIVERSAL__非定義として他プラットフォーム実装との共通名に#defineされる。定義/被定義が両者で逆だがソースコードには影響しない。

[include\wx\toplevel.h:375]

#if defined(__WXMSW__)
...
#define wxTopLevelWindowNative wxTopLevelWindowMSW
#elif ...
...
#endif

[include\wx\window.h:2070]

#if defined(__WXMSW__)
#ifdef __WXUNIVERSAL__
...
#else // !wxUniv
#define wxWindowMSW wxWindow
#endif // wxUniv/!wxUniv
...
#elif ...
...
#endif

イベントテーブル

[src\common\toplvcmn.cpp:37]

wxBEGIN_EVENT_TABLE(wxTopLevelWindowBase, wxWindow)
EVT_CLOSE(wxTopLevelWindowBase::OnCloseWindow)
EVT_SIZE(wxTopLevelWindowBase::OnSize)
wxEND_EVENT_TABLE()

Createメンバ関数

wxTopLevelWindowMSW::Createメンバ関数

[src\msw\toplevel.cpp:424]

bool wxTopLevelWindowMSW::Create(wxWindow *parent,
wxWindowID id,
const wxString& title,
const wxPoint& pos,
const wxSize& size,
long style,
const wxString& name)
{
wxSize sizeReal = size;
if ( !sizeReal.IsFullySpecified() )
{
sizeReal.SetDefaults(GetDefaultSize());
}
// notice that we should append this window to wxTopLevelWindows list
// before calling CreateBase() as it behaves differently for TLW and
// non-TLW windows
wxTopLevelWindows.Append(this);
if ( !CreateBase(parent, id, pos, sizeReal, style, name) )
return false;
if ( parent )
parent->AddChild(this);
...
return true;
}

~wxTopLevelWindowデストラクタ

IsLastBeforeExitメンバ関数コールで最後のTLWであればアプリケーションを終了する。解体されたTLWは基底wxWindowBaseデストラクタでwxwxPendingDeleteリストから削除される。

wxTopLevelWindowBase::~wxTopLevelWindowBaseデストラクタ

[src\common\toplvlcmn.cpp:58]

wxTopLevelWindowBase::~wxTopLevelWindowBase()
{
// don't let wxTheApp keep any stale pointers to us
if ( wxTheApp && wxTheApp->GetTopWindow() == this )
wxTheApp->SetTopWindow(NULL);
wxTopLevelWindows.DeleteObject(this);
// delete any our top level children which are still pending for deletion
// immediately: this could happen if a child (e.g. a temporary dialog
// created with this window as parent) was Destroy()'d) while this window
// was deleted directly (with delete, or maybe just because it was created
// on the stack) immediately afterwards and before the child TLW was really
// destroyed -- not destroying it now would leave it alive with a dangling
// parent pointer and result in a crash later
for ( wxObjectList::iterator i = wxPendingDelete.begin();
i != wxPendingDelete.end();
)
{
wxWindow * const win = wxDynamicCast(*i, wxWindow);
if ( win && wxGetTopLevelParent(win->GetParent()) == this )
{
wxPendingDelete.erase(i);
delete win;
// deleting it invalidated the list (and not only one node because
// it could have resulted in deletion of other objects to)
i = wxPendingDelete.begin();
}
else
{
++i;
}
}
if ( IsLastBeforeExit() )
{
// no other (important) windows left, quit the app
wxTheApp->ExitMainLoop();
}
}

wxTopLevelWindowBase::IsLastBeforeExitメンバ関数

[src\common\toplvcmn.cpp:143]

bool wxTopLevelWindowBase::IsLastBeforeExit() const
{
// first of all, automatically exiting the app on last window close can be
// completely disabled at wxTheApp level
if ( !wxTheApp || !wxTheApp->GetExitOnFrameDelete() )
return false;
// second, never terminate the application after closing a child TLW
// because this would close its parent unexpectedly -- notice that this
// check is not redundant with the loop below, as the parent might return
// false from its ShouldPreventAppExit() -- except if the child is being
// deleted as part of the parent destruction
if ( GetParent() && !GetParent()->IsBeingDeleted() )
return false;
wxWindowList::const_iterator i;
const wxWindowList::const_iterator end = wxTopLevelWindows.end();
// then decide whether we should exit at all
for ( i = wxTopLevelWindows.begin(); i != end; ++i )
{
wxTopLevelWindow * const win = static_cast<wxTopLevelWindow *>(*i);
if ( win->ShouldPreventAppExit() )
{
// there remains at least one important TLW, don't exit
return false;
}
}
// if yes, close all the other windows: this could still fail
for ( i = wxTopLevelWindows.begin(); i != end; ++i )
{
// don't close twice the windows which are already marked for deletion
wxTopLevelWindow * const win = static_cast<wxTopLevelWindow *>(*i);
if ( !wxPendingDelete.Member(win) && !win->Close() )
{
// one of the windows refused to close, don't exit
//
// NB: of course, by now some other windows could have been already
// closed but there is really nothing we can do about it as we
// have no way just to ask the window if it can close without
// forcing it to do it
return false;
}
}
return true;
}

wxWindowBase::~wxWindowBaseデストラクタ

[src\common\wincmn.cpp:453]

wxWindowBase::~wxWindowBase()
{
wxASSERT_MSG( !wxMouseCapture::IsInCaptureStack(this),
"Destroying window before releasing mouse capture: this "
"will result in a crash later." );
// FIXME if these 2 cases result from programming errors in the user code
// we should probably assert here instead of silently fixing them
// Just in case the window has been Closed, but we're then deleting
// immediately: don't leave dangling pointers.
wxPendingDelete.DeleteObject(this);
// Just in case we've loaded a top-level window via LoadNativeDialog but
// we weren't a dialog class
wxTopLevelWindows.DeleteObject(this);
...
}

Destroyメンバ関数

TLWは親ウィンドウが解体中でなければwxPendingDeleteに登録して解体遅延する。wxWakeUpIdle関数[src\common\appbase.cpp:1118]コール(wxTheApp->WakeUpIdleコールと等価)はバージョン3.1.4で追加された(※2)。

wxTopLevelWindowMSW::Destroyメンバ関数

[src\msw\toplevel.cpp:767]

bool wxTopLevelWindowMSW::Destroy()
{
if ( !wxTopLevelWindowBase::Destroy() )
return false;
// Under Windows 10 iconized windows don't get any messages, so delayed
// destruction doesn't work for them if we don't force a message dispatch
// here (and it doesn't seem useful to test for MSWIsIconized() as doing
// this doesn't do any harm for non-iconized windows either). For that
// matter, doing this shouldn't do any harm under previous OS versions
// either, so checking for the OS version doesn't seem useful too.
wxWakeUpIdle();
return true;
}

wxTopLevelWindowBase::Destroyメンバ関数

[src\common\toplvcmn.cpp:101]

bool wxTopLevelWindowBase::Destroy()
{
// We can't delay the destruction if our parent is being already destroyed
// as we will be deleted anyhow during its destruction and the pointer
// stored in wxPendingDelete would become invalid, so just delete ourselves
// immediately in this case.
wxWindow* parent = GetParent();
if ( (parent && parent->IsBeingDeleted()) || !GetHandle() )
{
return wxNonOwnedWindow::Destroy();
}
// delayed destruction: the frame will be deleted during the next idle
// loop iteration
if ( !wxPendingDelete.Member(this) )
wxPendingDelete.Append(this);
// normally we want to hide the window immediately so that it doesn't get
// stuck on the screen while it's being destroyed, however we shouldn't
// hide the last visible window as then we might not get any idle events
// any more as no events will be sent to the hidden window and without idle
// events we won't prune wxPendingDelete list and the application won't
// terminate
for ( wxWindowList::const_iterator i = wxTopLevelWindows.begin(),
end = wxTopLevelWindows.end();
i != end;
++i )
{
wxTopLevelWindow * const win = static_cast<wxTopLevelWindow *>(*i);
if ( win != this && win->IsShown() )
{
// there remains at least one other visible TLW, we can hide this
// one
Hide();
break;
}
}
return true;
}

wxWindowBase::Destroyメンバ関数

[src\common\wincmn.cpp:561]

bool wxWindowBase::Destroy()
{
// If our handle is invalid, it means that this window has never been
// created, either because creating it failed or, more typically, because
// this wxWindow object was default-constructed and its Create() method had
// never been called. As we didn't send wxWindowCreateEvent in this case
// (which is sent after successful creation), don't send the matching
// wxWindowDestroyEvent either.
if ( GetHandle() )
SendDestroyEvent();
delete this;
return true;
}

Closeメンバ関数

wxWindowBase::Closeメンバ関数

[src\common\wincmn.cpp:577]

bool wxWindowBase::Close(bool force)
{
wxCloseEvent event(wxEVT_CLOSE_WINDOW, m_windowId);
event.SetEventObject(this);
event.SetCanVeto(!force);
// return false if window wasn't closed because the application vetoed the
// close event
return HandleWindowEvent(event) && !event.GetVeto();
}

wxWindowBase::HandleWindowEventメンバ関数

wxWindowBase::GetEventHandlerメンバ関数[include\wx\window.h:862]はウィンドウのイベントハンドラ(デフォルトは自身)を返す。wxEvtHandler::SafelyProcessEventメンバ関数[src\common\event.cpp:1644]は例外処理を除けばwxEvtHandler::ProcessEventメンバ関数[src\common\event.cpp:1502]と同じ。

[src\common\wincmn.cpp:1550]

bool wxWindowBase::HandleWindowEvent(wxEvent& event) const
{
// SafelyProcessEvent() will handle exceptions nicely
return GetEventHandler()->SafelyProcessEvent(event);
}

OnCloseWindowメンバ関数

wxTopLevelWindowBase::OnCloseWindowメンバ関数

[src\common\toplvcmn.cpp:474]

void wxTopLevelWindowBase::OnCloseWindow(wxCloseEvent& WXUNUSED(event))
{
Destroy();
}

SendIdleEventsメンバ関数

wxWindowBase::SendIdleEventsメンバ関数

[src\common\wincmn.cpp:2835]

{.cpp]
bool wxWindowBase::SendIdleEvents(wxIdleEvent& event)
{
bool needMore = false;
OnInternalIdle();
// should we send idle event to this window?
if (wxIdleEvent::GetMode() == wxIDLE_PROCESS_ALL ||
HasExtraStyle(wxWS_EX_PROCESS_IDLE))
{
event.SetEventObject(this);
HandleWindowEvent(event);
if (event.MoreRequested())
needMore = true;
}
wxWindowList::compatibility_iterator node = GetChildren().GetFirst();
for (; node; node = node->GetNext())
{
wxWindow* child = node->GetData();
if (child->SendIdleEvents(event))
needMore = true;
}
return needMore;
}

MSWHandleMessageメンバ関数

wxWindowMSW::MSWHandleMessageメンバ関数

[src\msw\window.cpp:2957]

bool
wxWindowMSW::MSWHandleMessage(WXLRESULT *result,
WXUINT message,
WXWPARAM wParam,
WXLPARAM lParam)
{
// did we process the message?
bool processed = false;
// the return value
union
{
bool allow;
WXLRESULT result;
WXHBRUSH hBrush;
} rc;
// for most messages we should return 0 when we do process the message
rc.result = 0;
...
switch ( message )
{
...
case WM_QUERYENDSESSION:
processed = HandleQueryEndSession(lParam, &rc.allow);
break;
case WM_ENDSESSION:
processed = HandleEndSession(wParam != 0, lParam);
break;
...
}
if ( !processed )
return false;
*result = rc.result;
return true;
}

HandleQueryEndSessionメンバ関数

wxWindowMSW::HandleQueryEndSessionメンバ関数

[src\msw\window.cpp:4236]

bool wxWindowMSW::HandleQueryEndSession(long logOff, bool *mayEnd)
{
wxCloseEvent event(wxEVT_QUERY_END_SESSION, wxID_ANY);
event.SetEventObject(wxTheApp);
event.SetCanVeto(true);
event.SetLoggingOff(logOff == (long)ENDSESSION_LOGOFF);
bool rc = wxTheApp->SafelyProcessEvent(event);
if ( rc )
{
// we may end only if the app didn't veto session closing (double
// negation...)
*mayEnd = !event.GetVeto();
}
return rc;
}

HandleEndSessionメンバ関数

メインTLWがDestroyメンバ関数で解体遅延されればバージョン3.1.1以降(※1)でwxApp::GetMainTopWindowスタティックメンバ関数[src\common\appcmn.cpp:195]コール(wxTheApp->GetTopWindowコールと等価)はNULLを返してwxEVT_END_SESSIONイベントを発生しない。

wxWindowMSW::HandleEndSessionメンバ関数

[src\msw\window.cpp:4255]

bool wxWindowMSW::HandleEndSession(bool endSession, long logOff)
{
// do nothing if the session isn't ending
if ( !endSession )
return false;
// only send once
if ( this != wxApp::GetMainTopWindow() )
return false;
wxCloseEvent event(wxEVT_END_SESSION, wxID_ANY);
event.SetEventObject(wxTheApp);
event.SetCanVeto(false);
event.SetLoggingOff((logOff & ENDSESSION_LOGOFF) != 0);
return wxTheApp->SafelyProcessEvent(event);
}