Question

J'ai une classe d'observation et une classe d'abonné.
Aux fins de test, l'observateur crée un thread qui génère des messages faux et appels CServerCommandObserver::NotifySubscribers(), qui ressemble à ceci:

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 de CDialog, qui sont aussi hérite de CServerCommandSubscriber.

Dans la classe dérivée, j'ajouté une entrée de carte de message, que les commandes de serveur de routes vers le gestionnaire de la 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: 42

     

La valeur de l'ESP n'a pas été correctement   enregistrée à travers un appel de fonction. C'est   généralement le résultat d'appeler un   fonction déclarée avec un appel   convention avec un pointeur de fonction   a déclaré avec une vocation différente   convention.

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, ce que je dois chercher. Toutes les idées?

J'ai fait une autre observation étrange, qui pourrait être lié: Dans le NotifySubscribersmethod, je l'appelle IsWindow() pour vérifier si la fenêtre à laquelle les points de poignée, existe. Apparemment, il le fait. Mais appeler CWnd::FromHandlePermanent() renvoie un pointeur NULL.

Était-ce utile?

La solution 3

J'ai finalement décidé de le faire sans des messages de fenêtre et je suis affichons ma solution ici. Peut-être qu'il va aider quelqu'un d'autre.

Au lieu de laisser la fenêtre poste d'observateur des messages à ses abonnés, je laisse les données de vente d'observateur dans les tampons d'abonnés synchronisés. L'abonné de classe de dialogue utilise une minuterie pour vérifier périodiquement ses tampons et appeler les gestionnaires de winrar si ce ne sont pas vides.
Il y a quelques inconvénients:

  • Il est plus d'effort de codage parce que pour chaque type de données, les besoins d'un élément tampon à ajouter à l'abonné.
  • Il est également plus d'espace consommer, que les données existent pour chaque abonné et pas seulement une fois pendant l'appel SendMessage().
  • On doit également faire la synchronisation manuellement au lieu de compter sur le fil d'observateur étant suspendu alors que les messages sont traités.

A - OMI - énorme avantage est qu'il a mieux la sécurité de type. Il ne faut pas jeter quelques valeurs lParam dans des pointeurs en fonction de la valeur de wParam. À cause de cela, je pense que cette solution de contournement est très acceptable, sinon même supérieure à mon approche originale.

Autres conseils

De afxmsg_.h:

// for Registered Windows messages
#define ON_REGISTERED_MESSAGE(nMessageVariable, memberFxn) \
    { 0xC000, 0, 0, 0, (UINT_PTR)(UINT*)(&nMessageVariable), \
        /*implied 'AfxSig_lwl'*/ \
        (AFX_PMSG)(AFX_PMSGW) \
        (static_cast< LRESULT (AFX_MSG_CALL CWnd::*)(WPARAM, LPARAM) > \
        (memberFxn)) },

Ainsi, la signature est LRESULT ClassName::FunctionName(WPARAM, LPARAM), alors que le vôtre est void ClassName::FunctionName(const WPARAM, const LPARAM). Cela ne devrait pas compiler, au moins sous VS2008 il ne fonctionne pas.

Quelle est votre déclaration de HandleServerCommand dans la classe CServerCommandSubscriber (dans le fichier d'en-tête)?

  

Pour moi, cela semble compatible, n'est pas   il?

Syntaxiquement il semble de cette façon.

  

Je ne sais pas, ce que je dois regarder   pour. Toutes les idées?

Oui. J'ai eu le même problème lors de la compilation d'une bibliothèque de plug-in avec les paramètres de débogage et utilisé dans une application compilée de sortie-

En fait, les regards de problème comme une corruption de pile.

Puisque vous utilisez NotifySubscribers dans un thread séparé, utilisez PostMessage (ou PostThreadMessage) au lieu de SendMessage.

Cela peut ne pas être la cause réelle de l'accident, mais le changement devrait être fait de toute façon (que vous êtes un contexte de filetage de commutation en utilisant SendMessage sans GARDIENNAGE des données que ce soit.

Licencié sous: CC-BY-SA avec attribution
Non affilié à StackOverflow
scroll top