2013-05-14 3 views
1

Dans mon MainWindow j'ai un bouton qui peut être utilisé pour ouvrir un Process (appel natif OpenProcess) et d'effectuer des contrôles sur sa mémoire, mais la méthode appelée sur Click est asynchrone:A propos Async Tâches et élimination

<Button Content="Attach" Click="OnClickAttach"/> 

private async void OnClickAttach(Object sender, RoutedEventArgs e) 
{ 
    AttachmentResult result = await m_ViewModel.Attach(); 

    switch (result) 
     // Different MessageBox depending on the result. 
} 

maintenant, nous allons voir la partie ViewModel du code ...

// MemoryProcess class is just a wrapper for Process' handle and memory regions. 
private MemoryProcess m_MemoryProcess; 

public async Task<AttachmentResult> Attach() 
{ 
    AttachmentResult result = AttachmentResult.Success; 
    MemoryProcess memoryProcess = NativeMethods.OpenProcess(m_SelectedBrowserInstance.Process); 

    if (memoryProcess == null) 
     result = AttachmentResult.FailProcessNotOpened; 
    else 
    { 
     Boolean check1 = false; 
     Boolean check2 = false; 

     foreach (MemoryRegion region in memoryProcess) 
     { 
      // I perform checks on Process' memory regions and I eventually change the value of check1 or check2... 
      await Task.Delay(1); 
     } 

     if (!check1 && !check2) 
     { 
      NativeMethods.CloseHandle(memoryProcess.Handle); 
      result = AttachmentResult.FailProcessNotValid; 
     } 
     else 
     { 
      // I keep the Process opened for further use. I save it to a private variable. 
      m_MemoryProcess = memoryProcess; 
      m_MemoryProcess.Check1 = check1; 
      m_MemoryProcess.Check2 = check2; 
     } 
    } 

    return result; 
} 

maintenant ... voilà le problème. Lorsque l'utilisateur ferme l'application, si un Process est ouvert, je dois fermer correctement son handle. Donc, dans mon MainWindow je le code suivant:

protected override void OnClosing(CancelEventArgs e) 
{ 
    m_ViewModel.Detach(); 
    base.OnClosing(e); 
} 

Et dans mon ViewModel je le code suivant:

public void Detach() 
{ 
    if (m_MemoryProcess != null) 
    { 
     if (m_MemoryProcess.Check1) 
      // Do something... 

     if (m_MemoryProcess.Check2) 
      // Do something... 

     NativeMethods.CloseHandle(m_MemoryProcess.Handle); 
     m_MemoryProcess = null; 
    } 
} 

La méthode Attach() peut prendre très longtemps, plus de 2 minutes parfois. Je dois trouver une solution pour les problèmes suivants:

  • Si l'utilisateur ferme l'application tandis que la méthode Attach() est en cours d'exécution et avant memoryProcess est enregistré à la variable privée, la poignée Process ne sera pas fermée.
  • Si vous enregistrez l'instance MemoryProcess dans la variable privée juste au début de la méthode Attach(), l'utilisateur risque d'obtenir un NullReferenceException s'il ferme l'application alors que la méthode Attach() traite sa boucle foreach.
  • Je ne veux absolument pas que l'utilisateur attende la méthode Attach() pour terminer avant de le laisser fermer l'application. C'est horrible.

Comment est-ce que je peux faire ceci?

+0

Que diriez-vous quand ils ferment l'application, si l'appel ASYC n'a pas fini ... il suffit de cacher la fenêtre jusqu'à ce qu'il soit fini, puis fermez l'application réelle quand c'est fait –

+0

C'est aussi étrange parce que la méthode est assez intensive en CPU et si l'application va être fermée quand elle se termine ... bien , à quoi ça sert?! Le mieux serait de l'arrêter complètement ... c'est ce que j'essaie de faire. –

+0

Vous devriez utiliser SafeWin32Handle au lieu de IntPtr pour que vous puissiez vous débarrasser du gestionnaire au lieu de le fermer (ie le GC s'en débarrassera si vous oubliez.) Par exemple: public static extern SafeWin32Handle OpenProcess (int dwDesiredAccess, bool bInheritHandle, int dwProcessId); ' –

Répondre

1

OMI, si vous ne le faites pas explicitement et spécifiquement cibler pour créer différents processus détachés/indépendants comme, par exemple, par:

  • utilisant PInvoke.CreateProcess
  • utilisant

    (new System.Management.ManagementClass("Win32_ProcessStartup")) 
    .Properties["CreateFlags"].Value = 8; 
    
  • ou en conservant le processus enfant en vie à la fermeture de l'application en les lançant via des scripts shell distincts ou d'autres processus restant à exécuter après la fermeture de l'application;

  • créer un nouveau thread dans un autre processus indépendant utilisant CreateRemoteThread
  • etc.

ou des conclusions déjà exécuté indépendamment traite, vous n'avez pas besoin et probably should not "close" or dispose spawned by app processes. Windows (système opérant) fermera tout fichier généré par les processus d'application.

En outre, je crois qu'il est impossible d'exécuter du code dans une application une fois qu'elle a commencé à se fermer ou à se fermer.

PS (de commentaire hors-sujet):
je ne vois même pas que vous fermez (really one should kill) ou jetez vos processus dans votre code ...