public void Startup() { // Subscribe the windows events which tell us a title was changed _winEventObservable = WinEventHook.WindowTileChangeObservable() .Select(info => User32Api.GetText(info.Handle)) .Where(title => !string.IsNullOrEmpty(title)) .Subscribe(MonitorTitleChangeEvent); }
private async Task TestWinEventHook() { // This takes care of having a WinProc handler, to make sure the messages arrive var winProcHandler = WinProcHandler.Instance; // This buffers the observable var replaySubject = new ReplaySubject <IInteropWindow>(); var winEventObservable = WinEventHook.WindowTileChangeObservable() .Select(info => InteropWindowFactory.CreateFor(info.Handle).Fill()) .Where(interopWindow => !string.IsNullOrEmpty(interopWindow?.Caption)) .Subscribe(interopWindow => { Log.Debug().WriteLine("Window title change: Process ID {0} - Title: {1}", interopWindow.Handle, interopWindow.Caption); replaySubject.OnNext(interopWindow); }, exception => Log.Error().WriteLine("An error occured", exception)); await Task.Delay(100); // Start a process to test against using (var process = Process.Start("notepad.exe")) { try { // Make sure it's started Assert.NotNull(process); // Wait until the process started it's message pump (listening for input) process.WaitForInputIdle(); User32Api.SetWindowText(process.MainWindowHandle, "TestWinEventHook - Test"); // Find the belonging window var notepadWindow = await replaySubject.Where(info => info != null && info.ProcessId == process.Id).FirstAsync(); Assert.Equal(process.Id, notepadWindow?.ProcessId); } finally { winEventObservable.Dispose(); process?.Kill(); } } }
/// <summary> /// The OAuth code receiver /// </summary> /// <param name="authorizeMode">which of the AuthorizeModes was used to call the method</param> /// <param name="codeReceiverSettings"></param> /// <param name="cancellationToken">CancellationToken</param> /// <returns>Dictionary with values</returns> public async Task <IDictionary <string, string> > ReceiveCodeAsync(AuthorizeModes authorizeMode, ICodeReceiverSettings codeReceiverSettings, CancellationToken cancellationToken = default) { // Force OOB Uri, if nothing is set if (string.IsNullOrEmpty(codeReceiverSettings.RedirectUrl)) { switch (authorizeMode) { case AuthorizeModes.OutOfBound: codeReceiverSettings.RedirectUrl = "urn:ietf:wg:oauth:2.0:oob"; break; case AuthorizeModes.OutOfBoundAuto: codeReceiverSettings.RedirectUrl = "urn:ietf:wg:oauth:2.0:oob:auto"; break; default: throw new NotSupportedException($"Only {AuthorizeModes.OutOfBound} and {AuthorizeModes.OutOfBoundAuto} are supported modes for this receiver"); } } var uriBuilder = new UriBuilder(codeReceiverSettings.AuthorizationUri) { Query = codeReceiverSettings.AuthorizationUri.QueryToKeyValuePairs() .Select(x => new KeyValuePair <string, string>(x.Key, x.Value.FormatWith(codeReceiverSettings))) .ToQueryString() }; // Get the formatted FormattedAuthUrl var authorizationUrl = uriBuilder.Uri; Log.Debug().WriteLine("Opening a browser with: {0}", authorizationUrl.AbsoluteUri); // Open the url in the default browser var processStartInfo = new ProcessStartInfo(authorizationUrl.AbsoluteUri) { CreateNoWindow = true, UseShellExecute = true }; Process.Start(processStartInfo); Log.Debug().WriteLine("Waiting until a window gets a title with the state {0}", codeReceiverSettings.State); // Wait until a window get's a title which contains the state object var title = await WinEventHook.WindowTileChangeObservable() .Select(info => InteropWindowFactory.CreateFor(info.Handle).Fill()) .Where(interopWindow => !string.IsNullOrEmpty(interopWindow?.Caption)) .Where(interopWindow => interopWindow.Caption.Contains(codeReceiverSettings.State)) // Skip temporary titles, where the redirect URL os briefly seen .Where(interopWindow => interopWindow?.Caption.Contains(codeReceiverSettings.RedirectUrl) != true) .Select(interopWindow => interopWindow.Caption) .Take(1).ToTask(cancellationToken); Log.Debug().WriteLine("Got title {0}", title); if (string.IsNullOrEmpty(title)) { return(new Dictionary <string, string>()); } var match = QueryPartOfTitleRegEx.Match(title); if (!match.Success) { return(UriParseExtensions.QueryStringToDictionary(title)); } var queryParameters = match.Groups["query"]?.Value; if (string.IsNullOrEmpty(queryParameters)) { return(new Dictionary <string, string>()); } Log.Debug().WriteLine("Query parameters: {0}", queryParameters); // Return result of the listening return(UriParseExtensions.QueryStringToDictionary(queryParameters)); }