2009-09-30 4 views
2

J'utilise une série de tests WatiN qui permettent à IE d'effectuer des vérifications périodiques pour la surveillance d'un site.Invocation régulière d'un processus interactif (tests WatiN) via Task Scheduler

La suite fonctionne correctement lorsque je l'appelle de manière interactive et/ou lorsque je configure la tâche dans le Planificateur de tâches sur "Exécuter uniquement lorsque l'utilisateur est connecté". Toutefois, lorsque je l'ai défini sur "Exécuter si l'utilisateur est connecté ou non", cochez l'option "Exécuter avec les privilèges les plus élevés" (WatiN ne peut pas communiquer correctement avec le navigateur sous Windows Server 2008 et plusieurs autres WatiN ne peut pas communiquer avec ses instances iexplore.exe de manière satisfaisante (elles commencent, mais j'ai un timeout exception as detailed in this post). J'ai ajouté le site que je frappe aux sites de confiance pour les contextes admin et non-admin de IE. J'ai essayé avec et sans élévation, avec et sans désactiver ESC et avec et avec et sans désactiver le mode protégé pour la zone internet. Comme mes tests non-GUI sont satisfaisants, je suppose que c'est une limitation du type d'interactivité possible dans le contexte d'une tâche planifiée non-interactive, même lorsque "Exécuter avec les privilèges les plus élevés". Pour l'instant, ma solution de contournement temporaire consiste à exiger qu'une session [TS] reste ouverte à tout moment, prête à exécuter la tâche planifiée. Si je devais persister avec cela, j'ajouterais au minimum une notification de pulsation pour permettre à quelque chose de surveiller que la tâche commence réellement à s'exécuter [par exemple, si quelqu'un ferme la session ou redémarre la boîte].

Cependant, je cherche quelque chose de plus permanent - quelque chose qui est capable d'invoquer régulièrement mes tests WatiN [exécuter en utilisant xunit-console.x86.exe v 1.5] sur ma boîte Windows Server 2008 [x64], juste comme le planificateur de tâches mais avec une session interactive appropriée. Je préférerais ne pas utiliser psexec ou remcom si possible, et je ne vois pas comment créer un service Windows ferait autre chose que d'ajouter un autre point de défaillance, mais je serais intéressé d'entendre parler de toutes les solutions éprouvées Là.

Répondre

0

De l'invite de commande, vous pouvez planifier une tâche interactive comme ceci:

... où sc est le calendrier, st est le temps de démarrage, tn est le nom_tâche que vous choisissez (peut être n'importe quoi), et tr est la commande que vous voulez exécuter. Évidemment, pour une tâche récurrente, vous devez changer sc en mensuel, hebdomadaire, etc. Il suffit de taper "schtasks/create /?" pour plus d'informations.

+0

Pourquoi vous sentez-vous cette rencontre le ** comme le Planificateur de tâches, mais avec une bonne séance interactive ** provisio dans la question? Tout le problème est que le processus doit être interactif - avez-vous utilisé cette technique pour faire quelque chose de similaire dans la nature. ... ou ai-je oublié quelque chose? –

+0

Cette ligne dans ma réponse lance une invite de commande interactive dans la session console/admin de l'ordinateur, mais le cmd.exe peut être remplacé par un autre exécutable. J'ai peut-être mal compris votre question. – WEFX

+0

S'il y a 2 sessions TS ouvertes pour l'utilisateur A et B, comment comptez-vous que votre commande choisit la session à exécuter/est-il possible de lui en choisir une en dehors de l'utilisateur? WinXP où il n'y a qu'une seule session. AIUI J'ai besoin que le processus soit généré dans une session interactive - c'est-à-dire, un vrai bureau avec une vraie interface utilisateur. c'est-à-dire que cmd.exe doit être parenté par un processus dans une session connectée - pas seulement une fenêtre WindowStation non interactive. Pour être honnête, j'ai sorti la plupart de ce contexte car la question a été posée et je sais que je suis en train d'abîmer la terminologie dans ces commentaires! –

4

J'ai été en mesure d'exécuter des tests Watin en utilisant Tâche planifiée dans le mode "Exécuter si l'utilisateur est connecté ou non". Dans mon cas, j'ai suivi le problème jusqu'à m_Proc.MainWindowHandle étant toujours 0 lorsque IE est créé à partir d'une tâche planifiée exécutée sans utilisateur connecté. Dans sources Watin cela est dans les IE.cs: fonction CreateIEPartiallyInitializedInNewProcess

Ma solution consiste à énumérer manuellement les fenêtres de haut niveau et de trouver une fenêtre avec className == « IEFrame » qui appartient au processus au lieu d'utiliser la propriété Process.MainWindowHandle .

Voici l'extrait de code. Tout pinvoke j'ai copié directement à partir de la source Watin.

public static class IEBrowserHelper 
    { 
     private static Process CreateIExploreInNewProcess() 
     { 
      var arguments = "about:blank"; 

      arguments = "-noframemerging " + arguments; 

      var m_Proc = Process.Start("IExplore.exe", arguments); 
      if (m_Proc == null) throw new WatiN.Core.Exceptions.WatiNException("Could not start IExplore.exe process"); 

      return m_Proc; 
     } 
     class IeWindowFinder 
     { 
      #region Interop 
      [DllImport("user32.dll", SetLastError = true)] 
      static extern uint GetWindowThreadProcessId(IntPtr hWnd, out uint lpdwProcessId); 
      public delegate bool EnumWindowsProc(IntPtr hWnd, IntPtr lParam); 
      [DllImport("user32.dll", SetLastError = true)] 
      public static extern bool EnumWindows(EnumWindowsProc lpEnumFunc, IntPtr lParam); 
      [DllImport("user32", EntryPoint = "GetClassNameA", CharSet = CharSet.Ansi, SetLastError = true, ExactSpelling = true)] 
      internal static extern int GetClassName(IntPtr handleToWindow, StringBuilder className, int maxClassNameLength); 
      #endregion 

      readonly Process IeProcess; 
      IntPtr HWnd = IntPtr.Zero; 

      public IeWindowFinder(Process ieProcess) 
      { 
       this.IeProcess = ieProcess; 
      } 
      public IntPtr Find() 
      { 
       EnumWindows(FindIeWindowCallback, IntPtr.Zero); 
       return HWnd; 
      } 

      bool FindIeWindowCallback(IntPtr hWnd, IntPtr lParam) 
      { 
       uint processId; 
       GetWindowThreadProcessId(hWnd, out processId); 
       if (processId == IeProcess.Id) 
       { 
        int maxCapacity = 255; 
        var sbClassName = new StringBuilder(maxCapacity); 
        var lRes = GetClassName(hWnd, sbClassName, maxCapacity); 
        string className = lRes == 0 ? String.Empty : sbClassName.ToString(); 
        if (className == "IEFrame") 
        { 
         this.HWnd = hWnd; 
         return false; 
        } 
       } 
       return true; 
      } 
     } 

     public static WatiN.Core.IE CreateIEBrowser() 
     { 
      Process ieProcess = CreateIExploreInNewProcess(); 

      IeWindowFinder findWindow = new IeWindowFinder(ieProcess); 

      var action = new WatiN.Core.UtilityClasses.TryFuncUntilTimeOut(TimeSpan.FromSeconds(WatiN.Core.Settings.AttachToBrowserTimeOut)) 
      { 
       SleepTime = TimeSpan.FromMilliseconds(500) 
      }; 

      IntPtr hWnd = action.Try(() => 
      { 
       return findWindow.Find(); 
      }); 
      ieProcess.Refresh(); 
      return WatiN.Core.IE.AttachTo<WatiN.Core.IE>(
       new WatiN.Core.Constraints.AttributeConstraint("hwnd", hWnd.ToString()), 5); 
     } 
    } 

puis à la place de nouveau IE() utiliser IEBrowserHelper.CreateIEBrowser()

+0

Intéressant. Sur quels systèmes d'exploitation fonctionne-t-il? Personnellement, je n'ai plus cette exigence, donc je ne me sens pas à l'aise de penser à cela comme une solution, donc c'est un long chemin d'acceptation. Je ne peux pas imaginer réellement prendre une dépendance sur quoi que ce soit ce IRL hacky mais pour prendre le temps, voici un +1 –

+0

Cela fonctionne sur Win 2008 R2 et sur Windows 7, tous deux x64. – shurik

+0

J'ai cette exigence moi-même, a commencé à creuser et après rien que j'ai travaillé sur googlé a dû plonger plus profond et déboguer Watin. Cela fonctionne définitivement pour moi maintenant et le seul changement de code que j'ai fait décrit ci-dessus. Je ne comprends pas complètement pourquoi MainWindowHandle n'a pas fonctionné, j'ai aussi beaucoup joué avec IE et les paramètres de tâches, mais je pense que j'ai tout annulé et ça marche toujours. Merci pour +1 de toute façon :) mon premier post et premier +1 ici. – shurik

-2
 


    using (IE browser = IEBrowserHelper.CreateIEBrowser()) 
    { 
    browser.GoTo("www.yourwebaddress.com"); 
    browser.AutoClose = true; 

    //Do the rest of your WaTin work in here.. 
    } 

Le code ci-dessus par shurik fonctionne très bien aussi bien sur serveur Windows 2012 ainsi. Au départ, je devais être connecté en tant qu'administrateur, maintenant ma tâche fonctionne bien déconnecté de RDP et déconnecté. J'ai fourni l'utilisation ci-dessus pour aider les autres s'ils ne savaient pas comment utiliser la classe fournie ci-dessus.

Vous aurez également besoin d'inclure l'espace de noms à charge supplémentaire suivante ..

 

    using WatiN; 
    using System.Diagnostics; 
    using System.Runtime.InteropServices; 

+0

Pouvez-vous clarifier un peu - êtes-vous en train de dire qu'amorcer un compte donné en exécutant un cycle élevé du code cité signifie qu'il fonctionnera même si vous redémarrez le serveur [et que vous n'avez donc aucune session ouverte]? Si tel est le cas, vous pouvez ajouter des détails sur la façon dont vous déclenchez le runnning - c'est-à-dire que vous utilisez 'schtasks' ou un moteur de construction quelconque? –

+0

La seule façon de continuer à fonctionner était de laisser une session RDP Remote Desktop Session ouverte. Si une session de bureau n'était pas ouverte, cela ne fonctionnait pas. J'espère que cela répond à votre question. –

+0

À droite, mais mon message dit: «Pour l'instant, ma solution de contournement temporaire consiste à exiger qu'une session [TS] reste ouverte en tout temps, prête à exécuter la tâche planifiée. <- le peu dont j'essaye de m'éloigner! –

Questions connexes