ObserverクラスとSubscriberクラスがあります。
テストの目的で、オブザーバーは偽のメッセージと呼び出しを生成するスレッドを作成しますCServerCommandObserver::NotifySubscribers()
。これは次のようになります。
void CServerCommandObserver::NotifySubscribers(const Command cmd, void const * const pData)
{
// Executed in worker thread //
for (Subscribers::const_iterator it = m_subscribers.begin(); it != m_subscribers.end(); ++it)
{
const CServerCommandSubscriber * pSubscriber = *it;
const HWND hWnd = pSubscriber->GetWindowHandle();
if (!IsWindow(hWnd)) { ASSERT(FALSE); continue; }
SendMessage(hWnd, WM_SERVERCOMMAND, cmd, reinterpret_cast<LPARAM>(pData));
}
}
サブスクライバーはCDialog
派生クラスであり、からも継承しCServerCommandSubscriber
ます。
派生クラスに、サーバーコマンドをサブスクライバークラスハンドラーにルーティングするメッセージマップエントリを追加しました。
// Derived dialog class .cpp
ON_REGISTERED_MESSAGE(CServerCommandObserver::WM_SERVERCOMMAND, HandleServerCommand)
// Subscriber base class .cpp
void CServerCommandSubscriber::HandleServerCommand(const WPARAM wParam, const LPARAM lParam)
{
const Command cmd = static_cast<Command>(wParam);
switch (cmd)
{
case something:
OnSomething(SomethingData(lParam)); // Virtual method call
break;
case // ...
};
}
問題は、HandleServerCommand()メソッドで奇妙なクラッシュが発生することです。
これは次のようになります。
デバッグエラー!
プログラム:c:\ myprogram.exe
モジュール:
ファイル:i386 \ chkesp.c
行:42ESPの値は、関数呼び出し全体で適切に保存されませんでした。これは通常、ある呼び出し規約で宣言された関数を、別の呼び出し規約で宣言された関数ポインターで呼び出した結果です。
AfxBeginThread()が必要とする関数ポインターを確認しました。
typedef UINT (AFX_CDECL *AFX_THREADPROC)(LPVOID); // AFXWIN.H
static UINT AFX_CDECL MessageGeneratorThread(LPVOID pParam); // My thread function
私には、これは互換性があるように見えますね。
他に何を探す必要があるのかわかりません。何か案は?
私は別の奇妙な観察を行いました。これは関連している可能性があります。メソッドでは、ハンドルが指すウィンドウが存在するかどうかを確認するためNotifySubscribers
に呼び出します。IsWindow()
どうやらそうです。ただし、呼び出しCWnd::FromHandlePermanent()
はNULLポインターを返します。