8

I am writing a desktop application and in one part I go through OAuth 2.0 flow.

The steps are:

  1. Start process - open web browser with login page.
  2. User logs in and authorize my app.
  3. In a background I search for process with a specific name, save it (name) in app.
  4. At the end I close the web browser.

The problem is that if user had previously opened some tabs in web browser - in point 1. new tab is added and in point 4. everything is closed (web browser with all tabs).

Can you tell me if there is a way to close a single tab in web browser? Or maybe there is other/easier way to go through OAuth?

As a manual solution I will simply show info to the user “Now you can close this tab”, however I would like to do it automatically.

This is C# .Net 4.0 WPF project.

string strAuthUrl = "http://accounts.example.com/login",
       strAuthCode = string.Empty;

// Request authorization from the user (by opening a browser window):
ProcessStartInfo startInfo = new ProcessStartInfo(strAuthUrl);
startInfo.CreateNoWindow = false;

//1.        
Process.Start(startInfo);   
//2. - is happening in web browser
//3.        
do
{
    foreach (Process proc in Process.GetProcesses())
    {
        if (proc.MainWindowTitle.StartsWith("Success code="))
        {
            strAuthCode = proc.MainWindowTitle.ToString().Substring(13, 30);
//4.
            try
            {

                // Close process by sending a close message to its main window.
                proc.CloseMainWindow();
                // Free resources associated with process.
                proc.Close();
                // Wait 500 milisecs for exit
                proc.WaitForExit(500);

                //if proc has not exited so far - kill it
                if (proc.HasExited == false)
                {
                    proc.Kill();
                    proc.WaitForExit();
                }
            }
            catch (Exception ex)
            {
                //Do something with exception
            }

            break;
        }
    }
}
while (string.IsNullOrEmpty(strAuthCode));

Thanks for your suggestions.

H.B.
  • 166,899
  • 29
  • 327
  • 400
Tom K
  • 145
  • 1
  • 7
  • 1
    +1 for the most exotic way of implementing authentication I've ever seen – Sergey Kudriavtsev Mar 14 '12 at 13:54
  • More on topic: you might consider using one of existing C# OAuth libraries instead of this browser stuff - for example, from one of answers to http://stackoverflow.com/questions/3997172/oauth-2-0-service-provider-net-libraries – Sergey Kudriavtsev Mar 14 '12 at 13:56
  • 3
    You could just keep it in your application by using the native `WebBrowser` control. – H.B. Mar 14 '12 at 13:56
  • Force the url to load in a new instance of the default browser? http://stackoverflow.com/questions/742598/open-a-url-in-a-new-browser-process – Alex K. Mar 14 '12 at 13:59
  • 3
    Just use HttpWebRequest. No need to involve an external Web Browser. – Quintium Mar 14 '12 at 14:05

4 Answers4

2

As Stephen Lee Parker suggested, it is indeed possible to send a keystroke to a certain window. That is, given that you have the handle for your browser window.

Also, your browser of choise should support a hotkey for closing seperate tabs, but Ctrl+W works most of the time.

With:

using System.Runtime.InteropServices;

and

[DllImportAttribute("user32.dll", EntryPoint = "SetForegroundWindow")]
[return: MarshalAsAttribute(UnmanagedType.Bool)]
public static extern bool SetForegroundWindow([InAttribute()] IntPtr hWnd);

[DllImport("user32.dll")]
public static extern void keybd_event(byte bVk, byte bScan, uint dwFlags, uint dwExtraInfo);

byte W = 0x57; //the keycode for the W key

public static void Send(byte KeyCode, bool Ctrl, bool Alt, bool Shift, bool Win)
{
    byte Keycode = (byte)KeyCode;

    uint KEYEVENTF_KEYUP = 2;
    byte VK_CONTROL = 0x11;
    byte VK_MENU = 0x12;
    byte VK_LSHIFT = 0xA0;
    byte VK_LWIN = 0x5B;

    if (Ctrl)
        keybd_event(VK_CONTROL, 0, 0, 0);
    if (Alt)
        keybd_event(VK_MENU, 0, 0, 0);
    if (Shift)
        keybd_event(VK_LSHIFT, 0, 0, 0);
    if (Win)
        keybd_event(VK_LWIN, 0, 0, 0);

    //true keycode
    keybd_event(Keycode, 0, 0, 0); //down
    keybd_event(Keycode, 0, KEYEVENTF_KEYUP, 0); //up

    if (Ctrl)
        keybd_event(VK_CONTROL, 0, KEYEVENTF_KEYUP, 0);
    if (Alt)
        keybd_event(VK_MENU, 0, KEYEVENTF_KEYUP, 0);
    if (Shift)
        keybd_event(VK_LSHIFT, 0, KEYEVENTF_KEYUP, 0);
    if (Win)
        keybd_event(VK_LWIN, 0, KEYEVENTF_KEYUP, 0);

}

You can virtually send any Keycode on your keyboard to the currently active window. Since you can really easily set the foreground window using Win32, this should work on most applications.

You also can see that this code first 'presses down' any chosen modifier keys, then presses the key with your given keycode down before releasing everything, making it able to send CTRL+W for example.

    void CloseTab()
    {
       SetForegroundWindow(_browserWindow.Handle);
       Send(W, true, false, false, false); //Ctrl+W
    }

Good luck!,

(Also this is my first answer so I really hope i'm able to help some of you)

iKevenaar
  • 21
  • 4
  • Cheers! Old post, but you saved me from digging up alot of old w32 code :) – Stígandr Mar 03 '14 at 09:14
  • You are welcome! Since posting this answer I have learned that it is actually better to use the SendInput method instead of Keybd_Event. In some cases, like some fullscreen games, it will only work with SendInput. – iKevenaar Mar 31 '14 at 22:05
0

May be its too long to answer, but today I faced the same problem and I'm going to use this way: open the url in a new browser process. Open a URL in a new browser process

then after authentication or whatsoever you want; e.g. in my case; when user entered the pin into my WPF; generated from twitter, I can easily close individual process. In this way, you need not to worry about other tabs since a new browser process was opened.

Community
  • 1
  • 1
Raza Ahmed
  • 2,661
  • 2
  • 35
  • 46
0

I've done this by sending CTRL-W to the browser window...

Stephen Lee Parker
  • 1,215
  • 9
  • 19
0

There are other ways of doing this like using dotnetopenauth. But if you really want to use a web browser, I suggest you use the .Net WebBrowser control for the task, and handle the Navigated event to determine when to close it.

Reinaldo
  • 4,556
  • 3
  • 24
  • 24