/// <summary> /// Waits until window exists, is visible (optionally) and active (optionally). /// Returns window handle. On timeout returns default(AWnd) if <i>secondsTimeout</i> is negative; else exception. /// Parameters etc are the same as <see cref="Find"/>. /// </summary> /// <param name="secondsTimeout">Timeout, seconds. Can be 0 (infinite), >0 (exception) or <0 (no exception). More info: [](xref:wait_timeout).</param> /// <param name="active">The window must be the active window (<see cref="Active"/>), and not minimized.</param> /// <exception cref="TimeoutException"><i>secondsTimeout</i> time has expired (if > 0).</exception> /// <exception cref="Exception">Exceptions of <see cref="Find"/>.</exception> /// <remarks> /// By default ignores invisible and cloaked windows. Use flags if need. /// If you have a window's AWnd variable, to wait until it is active/visible/etc use <see cref="WaitForCondition"/> instead. /// </remarks> /// <example> /// <code><![CDATA[ /// AWnd w = AWnd.Wait(10, false, "* Notepad"); /// AOutput.Write(w); /// ]]></code> /// Using in a Form/Control event handler. /// <code><![CDATA[ /// var f = new Form(); /// f.Click += async (unu, sed) => /// { /// AOutput.Write("waiting for Notepad..."); /// AWnd w = await Task.Run(() => AWnd.Wait(-10, false, "* Notepad")); /// if(w.Is0) AOutput.Write("timeout"); else AOutput.Write(w); /// }; /// f.ShowDialog(); /// ]]></code> /// </example> public static AWnd Wait(double secondsTimeout, bool active, #pragma warning disable CS1573 // Parameter has no matching param tag in the XML comment (but other parameters do) [ParamString(PSFormat.AWildex)] string name = null, [ParamString(PSFormat.AWildex)] string cn = null, [ParamString(PSFormat.AWildex)] WOwner of = default, WFlags flags = 0, Func <AWnd, bool> also = null, WContains contains = default) #pragma warning restore CS1573 // Parameter has no matching param tag in the XML comment (but other parameters do) { var f = new Finder(name, cn, of, flags, also, contains); var to = new AWaitFor.Loop(secondsTimeout); for (; ;) { if (active) { AWnd w = Active; if (f.IsMatch(w) && !w.IsMinimized) { return(w); } } else { if (f.Find()) { return(f.Result); } } if (!to.Sleep()) { return(default);
//rejected: single overload with last parameter double? wait. // Then in scripts almost always would need eg ' , wait: 1'. Or would need ', wait: 0' just for 'exception if not found'. #pragma warning disable CS1573 // Parameter has no matching param tag in the XML comment (but other parameters do) /// <summary> /// Finds a top-level window and returns its handle as <b>wnd</b>. Can wait and throw <b>NotFoundException</b>. /// </summary> /// <returns>Window handle. If not found, throws exception or returns <c>default(wnd)</c> (if <i>waitS</i> negative).</returns> /// <param name="waitS">The wait timeout, seconds. If 0, does not wait. If negative, does not throw exception when not found.</param> /// <exception cref="NotFoundException" /> /// <exception cref="ArgumentException" /> /// <inheritdoc cref="find"/> public static wnd find( double waitS, [ParamString(PSFormat.Wildex)] string name = null, [ParamString(PSFormat.Wildex)] string cn = null, [ParamString(PSFormat.Wildex)] WOwner of = default, WFlags flags = 0, Func <wnd, bool> also = null, WContains contains = default ) => new wndFinder(name, cn, of, flags, also, contains).Find(waitS);
/// <summary> /// Adds a window trigger and its action. /// </summary> /// <param name="winEvent">Trigger event.</param> /// <param name="name">See <see cref="AWnd.Find"/>.</param> /// <param name="cn">See <see cref="AWnd.Find"/>.</param> /// <param name="of">See <see cref="AWnd.Find"/>.</param> /// <param name="also">See <see cref="AWnd.Find"/>.</param> /// <param name="contains">See <see cref="AWnd.Find"/>.</param> /// <param name="flags">Trigger flags.</param> /// <param name="later"> /// Can optionally specify one or more additional events. /// This starts to work when the primary trigger is activated, and works only for that window. /// For example, to be notified when the window is closed or renamed, specify <c>later: TWLater.Destroyed | TWLater.Name</c>. /// When a "later" event occurs, the trigger action is executed. The <see cref="WindowTriggerArgs.Later"/> property then is that event; it is 0 when it is the primary trigger. /// The "later" trigers are not disabled when primary triggers are disabled. /// </param> /// <exception cref="InvalidOperationException">Cannot add triggers after <c>Triggers.Run</c> was called, until it returns.</exception> /// <exception cref="ArgumentException">See <see cref="AWnd.Find"/>.</exception> /// <seealso cref="Last"/> public Action <WindowTriggerArgs> this[TWEvent winEvent, [ParamString(PSFormat.AWildex)] string name = null, [ParamString(PSFormat.AWildex)] string cn = null, [ParamString(PSFormat.AWildex)] WOwner of = default, Func <AWnd, bool> also = null, WContains contains = default, TWFlags flags = 0, TWLater later = 0 ] { set { var f = new AWnd.Finder(name, cn, of, 0, also, contains); this[winEvent, f, flags, later] = value; } }
#pragma warning restore CS1573 // Parameter has no matching param tag in the XML comment (but other parameters do) //rejected: probably most users will not understand/use it. It's easy and more clear to create and use wndFinder instances. ///// <summary> ///// Gets arguments and result of this thread's last call to <see cref="Find"/> or <see cref="FindAll"/>. ///// </summary> ///// <remarks> ///// <b>wnd.wait</b> and similar functions don't change this property. <see cref="FindOrRun"/> and some other functions of this library change this property because they call <see cref="Find"/> internally. ///// </remarks> ///// <example> ///// This example is similar to what <see cref="FindOrRun"/> does. ///// <code><![CDATA[ ///// wnd w = wnd.find("*- Notepad", "Notepad"); ///// if(w.Is0) { run.it("notepad.exe"); w = wnd.waitAny(60, true, wnd.LastFind).w; } ///// ]]></code> ///// </example> //[field: ThreadStatic] //public static wndFinder lastFind { get; set; } //CONSIDER: add property: [field: ThreadStatic] public static wnd last { get; set; } /// <summary> /// Finds all matching windows. /// Returns array containing 0 or more window handles as wnd. /// Parameters etc are the same as <see cref="find"/>. /// </summary> /// <exception cref="Exception">Exceptions of <see cref="find"/>.</exception> /// <remarks> /// The list is sorted to match the Z order, however hidden windows (when using <see cref="WFlags.HiddenToo"/>) and IME windows are always after visible windows. /// </remarks> /// <seealso cref="getwnd.allWindows"/> /// <seealso cref="getwnd.mainWindows"/> /// <seealso cref="getwnd.threadWindows"/> public static wnd[] findAll( [ParamString(PSFormat.Wildex)] string name = null, [ParamString(PSFormat.Wildex)] string cn = null, [ParamString(PSFormat.Wildex)] WOwner of = default, WFlags flags = 0, Func <wnd, bool> also = null, WContains contains = default) { var f = new wndFinder(name, cn, of, flags, also, contains); var a = f.FindAll(); //LastFind = f; return(a); }
/// <summary> /// Opens Task Scheduler UI for task editing. /// This process must be admin. /// Starts task and returns. /// </summary> /// <param name="taskFolder">See <see cref="RunTask"/>.</param> /// <param name="taskName">Task name (without path).</param> public static void EditTask(string taskFolder, string taskName) { Task.Run(() => { //run Task Scheduler UI var w = wnd.runAndFind( () => run.it(folders.System + "mmc.exe", folders.System + "taskschd.msc", flags: RFlags.InheritAdmin), 60, cn: "MMCMainFrame"); //expand folder "Task Scheduler Library" var tv = w.Child(id: 12785); tv.Focus(); var htvi = wait.forCondition(5, () => tv.Send(TVM_GETNEXTITEM, TVGN_CHILD, tv.Send(TVM_GETNEXTITEM))); wait.forCondition(10, () => 0 != tv.Send(TVM_EXPAND, TVE_EXPAND, htvi)); //note: don't wait for TVM_GETITEMSTATE TVIS_EXPANDED //open the specified folder var e = elm.fromWindow(tv, EObjid.CLIENT); e.Item = 2; taskFolder = taskFolder.Trim('\\').Replace('\\', '|'); e.Expand(taskFolder, waitS: 10, notLast: true).Select(); //open Properties dialog of the specified task var lv = w.Child(30, "***wfName listViewMain", "*.SysListView32.*"); //the slowest part, ~1 s lv.Elm["LISTITEM", taskName, flags: EFFlags.ClientArea | EFFlags.HiddenToo].Find(10).Select(); lv.Post(Api.WM_KEYDOWN, (int)KKey.Enter); //wait for task Properties dialog and select tab "Trigger" var wp = wnd.find(10, taskName + "*", "*.Window.*", WOwner.Process(w.ProcessId)); wp.Activate(); var tc = wp.Child(5, cn: "*.SysTabControl32.*"); tc.Send(TCM_SETCURFOCUS, 1); //never mind: the script may fail at any step, although on my computers never failed. // Let it do as much as it can. It's better than nothing. // Task.Run silently handles exceptions. }); }
TriggerScope _Window(bool not, string name, string cn, WOwner of, Func <AWnd, bool> also, WContains contains) => _Add(not, new AWnd.Finder(name, cn, of, 0, also, contains));
/// <summary> /// Sets scope "not this window". Hotkey, autotext and mouse triggers added afterwards will not work when the specified window is active. /// </summary> /// <returns>Returns an object that can be later passed to <see cref="Again"/> to reuse this scope.</returns> /// <remarks> /// Parameters are like with <see cref="AWnd.Find"/>. /// Example in class help. /// </remarks> /// <exception cref="ArgumentException">Exceptions of <see cref="AWnd.Finder"/> constructor.</exception> public TriggerScope NotWindow( [ParamString(PSFormat.AWildex)] string name = null, [ParamString(PSFormat.AWildex)] string cn = null, [ParamString(PSFormat.AWildex)] WOwner of = default, Func <AWnd, bool> also = null, WContains contains = default) => _Window(true, name, cn, of, also, contains);
#pragma warning disable CS1573 // Parameter has no matching param tag in the XML comment (but other parameters do) /// <summary> /// Waits until window exists or is active. /// </summary> /// <returns>Window handle. On timeout returns default(wnd) if <i>secondsTimeout</i> is negative; else exception.</returns> /// <param name="secondsTimeout">Timeout, seconds. Can be 0 (infinite), >0 (exception) or <0 (no exception). More info: [](xref:wait_timeout).</param> /// <param name="active">The window must be the active window (<see cref="active"/>), and not minimized.</param> /// <exception cref="TimeoutException"><i>secondsTimeout</i> time has expired (if > 0).</exception> /// <exception cref="ArgumentException" /> /// <remarks> /// Parameters etc are the same as <see cref="find"/>. /// By default ignores invisible and cloaked windows. Use <i>flags</i> if need. /// If you have a window's <b>wnd</b> variable, to wait until it is active/visible/etc use <see cref="WaitFor"/> instead. /// </remarks> /// <example> /// <code><![CDATA[ /// wnd w = wnd.wait(10, false, "* Notepad"); /// print.it(w); /// ]]></code> /// Using in a WPF window with async/await. /// <code><![CDATA[ /// using System.Windows; /// var b = new wpfBuilder("Window").WinSize(250); /// b.R.AddButton("Wait", async _ => { /// print.it("waiting for Notepad..."); /// wnd w = await Task.Run(() => wnd.wait(-10, false, "* Notepad")); /// if(w.Is0) print.it("timeout"); else print.it(w); /// }); /// if (!b.ShowDialog()) return; /// ]]></code> /// </example> /// <inheritdoc cref="find"/> public static wnd wait(double secondsTimeout, bool active, [ParamString(PSFormat.Wildex)] string name = null, [ParamString(PSFormat.Wildex)] string cn = null, [ParamString(PSFormat.Wildex)] WOwner of = default, WFlags flags = 0, Func <wnd, bool> also = null, WContains contains = default ) => new wndFinder(name, cn, of, flags, also, contains).Wait(secondsTimeout, active);