J'ai une classe Observer et une classe Subscriber.
Pour des fins de test, l'observateur crée un thread qui génère des messages faux et appelle CServerCommandObserver::NotifySubscribers()
, qui ressemble à ceci:Erreur ESP lors de l'envoi de messages de fenêtre entre threads
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));
}
}
L'abonné est une classe dérivée CDialog
, qui hérite aussi de CServerCommandSubscriber
.
Dans la classe dérivée, j'ai ajouté une entrée de mappe de message, qui route les commandes du serveur vers le gestionnaire de classe d'abonné.
// 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 // ...
};
}
Le problème est que je vois des accidents étranges dans la méthode HandleServerCommand():
Il ressemble à ceci:
Erreur de débogage!
Programme: c: \ myprogram.exe
Module:
fichier: i386 \ chkesp.c
Ligne: 42La valeur de l'ESP n'a pas été correctement enregistrée à travers un appel de fonction. Ceci est généralement le résultat de l'appel d'une fonction déclarée avec une convention appelant avec un pointeur de fonction déclaré avec une convention d'appel différente.
J'ai vérifié le pointeur de la fonction AfxBeginThread() veut avoir:
typedef UINT (AFX_CDECL *AFX_THREADPROC)(LPVOID); // AFXWIN.H
static UINT AFX_CDECL MessageGeneratorThread(LPVOID pParam); // My thread function
Pour moi, cela semble compatible, non?
Je ne sais pas, quoi d'autre je dois rechercher. Des idées?
J'ai fait une autre observation étrange, qui pourrait être lié: Dans la méthode NotifySubscribers
, je l'appelle IsWindow()
pour vérifier si la fenêtre à laquelle les points de poignée, existe. Apparemment, c'est le cas. Mais l'appel CWnd::FromHandlePermanent()
renvoie un pointeur NULL.
J'ai décidé de contourner le problème (voir ma propre réponse) et ne pourra pas essayer d'autres solutions car le code a beaucoup changé. – foraidt
'void const * const pData' - qu'est-ce que cela signifie? 'const void * pData' ne suffirait pas? Qu'est-ce que 'Command'? Je suppose que c'est un type simple puisque vous le passez comme valeur et non comme référence. –
@AOI 1: 'void const * const' signifie que le pointeur lui-même est garanti de ne pas être modifié dans sa portée. Le plus 'const 'le mieux mais oui, cela fonctionnerait avec un seul, aussi. 2: Oui, 'Command 'est juste un type' enum'. – foraidt