2010-03-23 17 views
1

Je crée un fil qui cherche une fenêtre. Quand il trouve la fenêtre, il remplace son windowproc et gère WM_COMMAND et WM_CLOSE.Sous-classe d'une fenêtre d'un fil dans C#

Voici le code qui recherche la fenêtre et sous-il:

public void DetectFileDialogProc() 
{ 
    Window fileDialog = null; 
    // try to find the dialog twice, with a delay of 500 ms each time 
    for (int attempts = 0; fileDialog == null && attempts < 2; attempts++) 
    { 
     // FindDialogs enumerates all windows of class #32770 via an EnumWindowProc 
     foreach (Window wnd in FindDialogs(500)) 
     {    
     IntPtr parent = NativeMethods.User32.GetParent(wnd.Handle); 
     if (parent != IntPtr.Zero) 
     { 
      // we're looking for a dialog whose parent is a dialog as well 
      Window parentWindow = new Window(parent); 
      if (parentWindow.ClassName == NativeMethods.SystemWindowClasses.Dialog) 
      { 
       fileDialog = wnd; 
       break; 
      } 
     } 
     } 
    } 
    // if we found the dialog 
    if (fileDialog != null) 
    { 
     OldWinProc = NativeMethods.User32.GetWindowLong(fileDialog.Handle, NativeMethods.GWL_WNDPROC); 
     NativeMethods.User32.SetWindowLong(fileDialog.Handle, NativeMethods.GWL_WNDPROC, Marshal.GetFunctionPointerForDelegate(new WindowProc(WndProc)).ToInt32()); 
    } 
} 

Et le WindowProc:

public IntPtr WndProc(IntPtr hWnd, uint msg, IntPtr wParam, IntPtr lParam) 
{ 
    lock (this) 
    { 
     if (!handled) 
     { 
     if (msg == NativeMethods.WM_COMMAND || msg == NativeMethods.WM_CLOSE) 
     {  
      // adding to a list. i never access the window via the hwnd from this list, i just treat it as a number 
      _addDescriptor(hWnd); 
      handled = true; 
     } 
     } 
    } 
    return NativeMethods.User32.CallWindowProc(OldWinProc, hWnd, msg, wParam, lParam); 
}   

Tout cela fonctionne bien dans des conditions normales. Mais je vois deux cas de mauvais comportement afin de badness:

  1. Si je ne ferme pas la boîte de dialogue dans une minute, les accidents de l'application. Est-ce parce que le fil récupère les ordures? Cela aurait un sens, dans la mesure où GC peut dire que le fil est fait? Si c'est le cas, (et je ne sais pas si c'est le cas), comment puis-je faire en sorte que le fil reste tant que la boîte de dialogue est ouverte? Si je ferme immédiatement la boîte de dialogue avec le bouton 'X' (WM_CLOSE), l'application se bloque. Je crois que c'est crash dans le windowproc, mais je ne peux pas obtenir un point d'arrêt là-bas. Je reçois une exception AccessViolationException, l'exception dit "Tentative de lecture ou d'écriture de la mémoire protégée, ce qui indique souvent qu'une autre mémoire est corrompue". C'est une condition de course, mais de ce que je ne sais pas. Pour info, j'avais remis à jour l'ancien windowproc une fois que j'avais traité les commandes, mais ça se brisait encore plus souvent!

Des idées sur la façon dont je peux résoudre ces problèmes?

Répondre

0

est finalement arrivé à une solution, d'attaquer le problème sous un angle différent. J'ai été en mesure de définir un crochet système dans le code managé en utilisant SetWinEventHook, et l'option WINEVENT_OUTOFCONTEXT, qui a la propriété étonnamment: La fonction de rappel n'est pas mappée dans l'espace d'adressage du processus qui génère l'événement. Je piège l'événement EVENT_SYSTEM_DIALOGSTART pour recevoir des notifications chaque fois qu'une boîte de dialogue est créée, et EVENT_SYSTEM_DIALOGEND lorsqu'il est détruit.

+0

il est appelé un «crochet d'accessibilité», ils sont différents des crochets de fenêtres ordinaires –

0

Deux points d'observation que je peux faire ....

  • Dans votre DetectFileDialogProc, vous comparez wnd à null, c'est un type IntPtr oui? le cas échéant, que l'enregistrement pour la comparaison doit être if (wnd > IntPtr.Zero){ .... }
  • Dans votre WndProc, vous utilisez la variable this pour la lock qui est une mauvaise chose à faire ... vous devriez faire quelque chose comme ça private readonly object objLock = new object(); et dans votre WndProc utiliser cette lock (objLock){....}

et voir si cela résout le problème ....