Comment puis-je empêcher mon application de recevoir un certain "message"?

SOLUTION TROUVÉE!

je crois avoir trouvé une solution! Je vais continuer à tester pour s'assurer qu'il ne fonctionne en fait, mais je suis optimiste :) j'ai détaillé comment j'ai trouvé la solution dans L'édition trois de la question!

pour toute personne souhaitant connaître le contexte complet derrière mon problème et ce que j'ai en quelque sorte essayé à la suite de l'entrée de cette question, voir ceci: http://pastebin.com/nTrEAkVj

je vais éditer ceci fréquemment (>3 fois par jour la plupart des jours de semaine) que je progresse ma recherche et la situation, alors continuez à vérifier si vous êtes intéressé ou avez une certaine information ou la connaissance de mon numéro:)

Rapide De Fond:

j'ai cette application que j'ai fait qui peut être écrasé en changeant mon épargnant d'écran ou de verrouillage de mon poste de travail, et en général chaque fois qu'un Le message WM_WININICHANGE/WM_SETTINGSCHANGE lui est envoyé.

si je peux toujours planter mon application en changeant mon screensaver, alors une partie de faire qui envoie mon application une sorte de message (pas nécessairement un message windows, je veux dire message dans le sens le plus général), qui à son tour est catastrophique pour mon application. Pour cette raison, j'essaie de trouver un moyen de bloquer tout message qui provoque mon problème d'être traité par mon application. Je suis conscient que ce n'est pas le la meilleure façon de trouver une solution, donc tu n'as pas besoin de me le dire. Regardez les informations de fond ou demandez pourquoi si cela vous dérange (il ya une bonne raison).

Ma Question:

il y a plusieurs choses sur lesquelles toute information pourrait m'aider à résoudre mon problème, étiquetées en fonction de la pertinence (1 étant la plus pertinente, 3 légèrement moins utile):

  1. j'essaie D'utiliser Wndproc() pour filtrer mon message comme ceci:

    Protected Overrides Sub WndProc(ByRef m As System.Windows.Forms.Message)
        If CInt(m.Msg) <> CInt(26) then
            MyBase.WndProc(m)
        end if
    End Sub
    

    cependant, selon Windspector, le message WM_WINININICHANGE est toujours envoyé à mon application (cela a du sens), mais il est également retourné avec 0... ça ne devrait pas arriver si ça marchait correctement, ça ne devrait rien rapporter, n'est-ce pas? Des informations sur les raisons pour lesquelles cela ne fonctionne pas comme je l'espérais et comment le faire fonctionner seraient extrêmement utiles!

  2. I ont également essayé d'utiliser messagefilters:

    Public Class MyMessageFilter
        Implements IMessageFilter
        Public Function PreFilterMessage(ByRef m As Message) As Boolean Implements IMessageFilter.PreFilterMessage
            ' Return true for messages that you want to stop  << someone elses comment       
            Return m.Msg = 26
        End Function
    End Class
    

    et puis Ajouter à ma mybase.méthode de manutention de la charge:

    de l'Application.AddMessageFilter (New MyMessageFilter ())

    cependant ils semblent filtrer seulement certains messages, et des messages comme le mien ne sont pas pris dans ceux apparemment. information sur s'il est definately impossible d'utiliser n'importe quel type de filtre pour attraper un message WM_ ou s'il y a peut-être d'autres façons d'utiliser filtres de message pour accomplir mon but serait également utile.

  3. dans quelles autres façons (à part de ce message de windows avec le message.msg = WM_WININICHANGE = 26 que j'ai trouvé) pourrais-je changer mon screensaver envoyer N'importe quel type de message à mon application? est-il possible qu'un autre type de message de changer mon épargnant d'écran soit également fatal?

faites-moi savoir s'il y a d'autres informations concernant ma situation qui peut être utile, et je ferai de mon mieux pour l'obtenir! Je vous remercie d'avance pour toute aide que vous pouvez donner :)

EDIT:

il apparaît si je n'envoie que le message de configuration de WM_CHANGESETTING, et que je fais attendre mon programme pendant la durée d'expiration du sendmessagetimeout avec lequel j'ai envoyé le message, alors mon programme ne se bloque pas... il semble que la réponse soit ce qui bloque mon programme... intéressant. Je suis vraiment proche de ma solution! Je pense qu'un peu plus de tests devrait me permettre de trouver une méthode pour m'assurer que mon programme ne répond pas au message.

MODIFIER LES DEUX:

j'ai découvert quelque chose de très prometteur aujourd'hui: j'ai défini ma fonction wndproc exactement comme ceci:

Protected Overrides Sub WndProc(ByRef m As System.Windows.Forms.Message)
    If CInt(m.Msg) <> CInt(26) Then
        MyBase.WndProc(m)
    Else
        MessageBox.Show("Get to work!", "Attention", MessageBoxButtons.OK, MessageBoxIcon.Exclamation, MessageBoxDefaultButton.Button1, MessageBoxOptions.ServiceNotification)
    End If
End Sub

et puis j'ai essayé d'exécuter mon programme, puis d'envoyer un message WM_SETTINGCHANGE en utilisant:

SendMessageTimeout(HWND_BROADCAST, WM_SETTINGCHANGE, IntPtr.Zero, IntPtr.Zero, _
             SendMessageTimeoutFlags.SMTO_ABORTIFHUNG, 5000, IntPtr.Zero)

dans un autre programme que j'ai fait. Donc ce qui est arrivé, demandez-vous? bien j'ai essayé ceci plusieurs fois, et chaque fois que le messagebox surgissait (les mots que j'ai choisis pour elle sont insignifiants), alors j'ai essayé d'attendre différentes quantités de temps avant d'appuyer sur ok, et alors je verrais ce qui est arrivé à ma forme principale. La plupart du temps, rien n'était différent, il s'écrasait quand même. Mais de temps en temps, peut-être 1/5 fois, le programme serait encore respoding après! Ensuite, si elle le faisait, je voudrais essayer d'envoyer le message encore, et puis encore, habituellement ils échouaient la deuxième fois au cours de la même course du programme, mais de temps en temps encore, environ un autre 1/5 fois il semblait, le programme ne se plantait pas à nouveau. Et puis les fois où j'ai essayé de le planter deux fois. et ce n'était pas l'une ou l'autre fois, il ne s'écrasait presque jamais, peu importe le nombre de fois où j'ai essayé d'envoyer le message et peu importe combien de temps j'ai attendu après que la boîte aux lettres soit apparue.

j'ai trouvé attendre environ 5 secondes semblait pour augmenter mes chances: ma forme que je déclenche le message avec serait toujours en focus (barre du haut serait bleu), juste après que j'ai appuyé sur le bouton freeze, et puis la boîte MSG apparaîtrait, avec le haut aussi bleu (en focus je suppose), tous les deux encore "en focus" (au moins haha bleu). Puis après environ 5 secondes la forme originale perdrait la mise au point, et après avoir vu cela, j'essayerais de frapper ok.

je pense actuellement que cette attente un peu et puis reconnaître le la boîte de message permet parfois à mon programme de ne pas s'écraser parce qu'il chronomètre le message pour qu'il ne revienne pas. Je ne sais pas pourquoi le retour du message ou non devrait avoir un effet sur ce que mon programme fait réellement. C'est la zone où des précisions seraient utiles :)

MODIFIER LES TROIS:

donc je cherche dans Winspector un peu plus, et je trouve que si j'attends WM_ERASEBKGND pour apparaître dans ma fenêtre de bureau (qui est la fenêtre étiquetée comme "sysListView32 'FolderView'" dans Winspector) avant de frapper "OK" sur ma msgbox, puis le programme ne va pas planter, intéressant! Il faut généralement proche du délai pour que le sendmessagetimeout pour le message WM_ERASEBKGND apparaisse. c'est bien sûr après avoir envoyé le message WM_SETTINGCHANGE depuis mon application de test maison.

donc, après cela je décide de regarder un peu plus autour de Winspector, parce que peut-être Il ya encore plus de files d'attente utiles que je peux trouver? Puisque évidemment attendre que winspector montre un message est envoyé à mon bureau n'est pas un correctif réel du tout pour mon programme. Je trouve quelques fenêtres inhabituellement nommées dans mon processus de programme: l'une est nommée ".NET-BroadcastEventWindow.2.0.0.0.378734 A. 0" et un autre est nommé "GDI+ Hook Window Class' GDI+ Window '"avec un sous-paramètre appelé" IME 'Default IME'".

je décide de regarder les messages d'aller à ces fenêtres pour voir s'ils reçoivent tout reconnaissable messages, comme WM_SETTINGCHANGE ou WM_ERASEBKGND. Il s'avère qu'ils ne reçoivent pas souvent de messages: GDI+ n'a pas reçu de messages pendant que je regardais I don't think, mais .NET-BroadcastEventWindow en a reçu quelques-uns. Ceux qui allaient à la fenêtre BroadcastEventWindow étaient principalement WM_appactivate lorsque j'ai cliqué sur ma fenêtre d'application ou une autre fenêtre après elle.

MAIS ALORS... Je remarque. Net BroadcastEventWindow reçoit mon message WM_CHANGESETTING!!!! Je regarde ce que les autres messages montrent: pas beaucoup, mais je remarque que lorsque l'application plante à cause du bogue, il y a un message que je ne reconnais pas: WM_USER+7194 (0x201a). Hm, permet de voir ce qui est. Après que je google it, je me rends compte qu'il semble être une application/message défini par l'utilisateur, et puis après une autre recherche sur les problèmes liés à elle, je remarque que quelqu'un est en mesure d'utiliser un filtre pour filtrer ce message et corriger un problème de la leur ( http://www.pcreview.co.uk/forums/handling-wm_user-messages-t1315625.html ). Il vaut la peine d'essayer pour moi, au moins? j'ajoute donc à nouveau le filtre que j'avais essayé auparavant, et change les valeurs à filtrer. L'application n'a pas de crash!!!!!!!

ensuite j'essaie de laisser mon poste de travail se verrouiller pour voir si ça le bloque encore (parce qu'auparavant c'était seulement avec l'envoi du seul message WM_CHANGESETTING). il s'avère qu'il s'est quand même écrasé :( mais, je jette un autre coup d'oeil dans winspector pour cette fenêtre, et oh huh, deux nouveaux messages WM_USER: WM_USER+7294(0x207E) et WM_USER+7189 (0x2015). J'ai donc essayer de filtrage de ces trop... et puis il ne s'écrase pas sur le verrouillage du poste de travail non plus!!! : D

jusqu'à présent, je n'ai pas remarqué d'effets indésirables de ce sur l'utilisation régulière de l'application aussi! ce qui est logique, puisque je ne pense pas que des messages définis par l'utilisateur soient délibérément impliqués dans mon programme.

je vais laisser la question ouverte un peu plus longtemps jusqu'à ce que je m'assure qu'il n'y a rien de mal avec ma solution et cela fonctionne bien. Merci à ceux d'entre vous qui m'ont donné quelques conseils sur la façon de procéder au milieu de mon débogage:)

27
demandé sur Cœur 2012-01-25 06:37:54

2 réponses

j'ai vu ce problème mentionné dans diverses questions au fil des ans. Jamais complètement diagnostiqué, je vais juste vous dire ce que j'en sais.

ce problème est lié à la façon dont la classe SystemEvents est initialisée. Il est impliqué dans l'accident, parce que c'est la classe qui déclenche l'événement qui se déclenche lorsque vous basculez sur le bureau sécurisé. Soit par l'intermédiaire de l'économiseur d'écran, soit en verrouillant le poste de travail (touche Windows + l). Les commandes Winforms sont en général intéressés par la SystemEvents.DisplaySettingsChanged événement parce qu'ils pourraient avoir besoin de se redessiner lorsque le thème ou les couleurs du système ont été changés. Cet événement est également souvent soulevé lorsque le système commute les ordinateurs de bureau.

L'un des principaux problèmes est que les événements doivent être soulevés sur le fil UI. SystemEvents doit deviner exactement ce que thread est en fait le thread UI. Cela va mal lorsque la toute première fenêtre qui est créée dans le programme est créé sur un fil qui n'est pas réellement le fil UI et se fait passer pour un fil en ayant son appartement COM réglé à STA. Si le thread continue à fonctionner, alors l'événement est déclenché sur ce thread. Si le thread est parti, ce qui n'est pas rare, alors une exception est soulevée lorsque le contexte de synchronisation.Post() tente de mobiliser l'appel et échoue. L'exception est avalée et l'événement est alors soulevé sur un ThreadPool arbitraire.

dans les deux cas, le l'événement n'est pas soulevé sur le thread correct et cela viole les exigences de threading pour n'importe quelle composante D'UI. Cela tend à passer inaperçu, pour quelque raison étrange le même événement déclenché sur le commutateur de bureau tend à causer l'impasse ou les accidents beaucoup plus souvent.

Vous aurez besoin d'examiner attentivement le code d'initialisation du programme. De loin, l'erreur la plus commune est de créer votre propre écran de démarrage. Assurez-vous d'utiliser le soutien intégré dans le .net framework pour bien faire.

6
répondu Hans Passant 2017-05-23 12:10:04

implémentez votre propre filtre de message avec

Public Class MyMessageFilter
    Implements IMessageFilter

    Public Function PreFilterMessage(ByRef m As Message) As Boolean Implements IMessageFilter.PreFilterMessage
        ' Return true for messages that you want to stop
        Return m.Msg = MessageToDiscard
    End Function
End Class

ajouter ce filtre lorsque votre application commence par

Application.AddMessageFilter(New MyMessageFilter())
4
répondu Olivier Jacot-Descombes 2012-01-25 17:23:28