Search code examples
c#webbrowser-controlwindows-live

Prevent WebBrowser Control in C# from launching external IE pop-up when logging into Windows Live


This is for a Desktop C# app in Visual Studio 2012.

I need to use a WebBrowser control in C# to log into a Windows Live instance, getting the control to open the page is nothing, but signing in is causing me a headache.

I've tried about 4 different suggestions gleaned from Google, but I'm not getting logged in properly.

This is what I've got:

//FORM1 code
//Added reference to 'Microsoft Internet Controls'
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows.Forms;

namespace WindowsFormsApplication3
{
    public partial class Form1 : Form
    {
        public Form1()
        {
            InitializeComponent();
            webBrowser1.Url = new Uri("http://digitbot.com/live/");
        }
        SHDocVw.WebBrowser nativeBrowser;
        protected override void OnLoad(EventArgs e)
        {
            base.OnLoad(e);
            nativeBrowser = (SHDocVw.WebBrowser)webBrowser1.ActiveXInstance;
            nativeBrowser.NewWindow2 += nativeBrowser_NewWindow2;
        }
        protected override void OnFormClosing(FormClosingEventArgs e)
        {
            nativeBrowser.NewWindow2 -= nativeBrowser_NewWindow2;
            base.OnFormClosing(e);
        }

        void nativeBrowser_NewWindow2(ref object ppDisp, ref bool Cancel)
        {
            var popup = new Form2();
            popup.Show(this);
            ppDisp = popup.Browser.ActiveXInstance;
        }
    }
}



//FORM2 code
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows.Forms;

namespace WindowsFormsApplication3
{
    public partial class Form2 : Form
    {
        public Form2()
        {
            InitializeComponent();
        }
        public WebBrowser Browser
        {
            get { return webBrowser1; }
        }
    }
}

This launches the login pop-up in the second window, but somehow it never seems to complete the process.

Following the link in the code above in a browser should get you logged in and should show raw JSON of calendar events followed by a profile picture. I need to get the same result in the WebBrowser control.

Any help would be great, I'm stuck.


Solution

  • Never got my initial approach to work, so I switched to using a WebClient and Browser with REST server-side since I needed to do stuff with the user logged out.

    This is the basic setup on the C# Windows 8 side with WPF:

    static string client_id = "your-client-id";
    static string client_secret = "your-client-secret";
    static string accessTokenUrl = 
      String.Format(@"https://login.live.com/oauth20_token.srf?client_id={0}&client" + 
      @"_secret={1}&redirect_uri=https://login.live.com/oauth20_desktop.srf&grant_type" + 
      @"=authorization_code&code=", client_id, client_secret);
    static string apiUrl = @"https://apis.live.net/v5.0/";
    public Dictionary<string, string> tokenData = new Dictionary<string, string>(); 
    

    This is the bulk of the code in my main window:

    private void getAccessToken()
    {
        if (App.Current.Properties.Contains("auth_code"))
        {
            makeAccessTokenRequest(accessTokenUrl + App.Current.Properties["auth_code"]);
        }
    }
    
    private void makeAccessTokenRequest(string requestUrl)
    {
        try
        {
            WebClient wc = new WebClient();
            wc.DownloadStringCompleted += new DownloadStringCompletedEventHandler(accessToken_DownloadStringCompleted);
            wc.DownloadStringAsync(new Uri(requestUrl));
            lError.Content = "";
        }
        catch (Exception ex)
        {
            lError.Content = "There has been an internet connection error.";
        }
    }
    
    void accessToken_DownloadStringCompleted(object sender, DownloadStringCompletedEventArgs e)
    {
        tokenData = deserializeJson(e.Result);
        if (tokenData.ContainsKey("access_token"))
        {
            App.Current.Properties.Add("access_token", tokenData["access_token"]);
            App.Current.Properties.Add("refresh_token", tokenData["refresh_token"]);
            getUserInfo();
        }
    }
    
    private Dictionary<string, string> deserializeJson(string json)
    {
        var jss = new JavaScriptSerializer();
        var d = jss.Deserialize<Dictionary<string, string>>(json);
        return d;
    }
    
    private void getUserInfo()
    {
        if (App.Current.Properties.Contains("access_token"))
        {
            try
            {
                makeApiRequest(apiUrl + "me?access_token=" + App.Current.Properties["access_token"]);
                lError.Content = "";
            }
            catch (Exception ex)
            {
                lError.Content = "There has been an internet connection error.";
            }
        }
    }
    
    private void makeApiRequest(string requestUrl)
    {
        try
        {
            WebClient wc = new WebClient();
            wc.DownloadStringCompleted += new DownloadStringCompletedEventHandler(client_DownloadStringCompleted);
            wc.DownloadStringAsync(new Uri(requestUrl));
            lError.Content = "";
        }
        catch (Exception ex)
        {
            lError.Content = "There has been an internet connection error.";
        }
    }
    
    void client_DownloadStringCompleted(object sender, DownloadStringCompletedEventArgs e)
    {
        changeView(e.Result);
    }
    
    private void changeView(string result)
    {
        string imgUrl = apiUrl + "me/picture?access_token=" + App.Current.Properties["access_token"];
        imgUser.Source = new BitmapImage(new Uri(imgUrl, UriKind.RelativeOrAbsolute));
        String code = "" + App.Current.Properties["refresh_token"];
        String auth = "" + App.Current.Properties["access_token"];
    
    }
    
    void browser_Closed(object sender, EventArgs e)
    {
        try
        {
            getAccessToken();
            lError.Content = "";
        }
        catch (Exception ex)
        {
            lError.Content = "There has been an internet connection error.";
        }
    } 
    

    The Windows Live authorization will then happen in this browser and go away once we're logged in.

    XAML for the browser:

    <Window x:Class="WpfApplication3.BrowserWindow"
          xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
          xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
          Title="Sign In" Height="460" Width="423.881" 
          ShowInTaskbar="False" WindowStartupLocation="CenterScreen">
        <Grid>
            <WebBrowser Height="419" HorizontalAlignment="Left" 
               Name="webBrowser" VerticalAlignment="Top" 
               Width="406" LoadCompleted="webBrowser_LoadCompleted" />
        </Grid>
    </Window>
    

    And here's the browser code:

    using System;
    using System.Collections.Generic;
    using System.Linq;
    using System.Text;
    using System.Windows;
    using System.Windows.Controls;
    using System.Windows.Data;
    using System.Windows.Documents;
    using System.Windows.Input;
    using System.Windows.Media;
    using System.Windows.Media.Imaging;
    using System.Windows.Shapes;
    using System.Text.RegularExpressions;
    
    namespace WpfApplication3
    
    {
        public partial class BrowserWindow : Window
        {
            static string scope = "wl.signin wl.calendars wl.offline_access wl.contacts_calendars";
            static string client_id = "your-client-id";
            static Uri signInUrl = new Uri(String.Format(@"https://login.live.com/oauth20" + 
              @"_authorize.srf?client_id={0}&redirect_uri=https://login.live.com/" + 
              @"oauth20_desktop.srf&response_type=code&scope={1}", client_id, scope));
            MainWindow mainWindow = new MainWindow();
    
            public BrowserWindow()
            {
                InitializeComponent();
                webBrowser.Navigate(signInUrl);
            }
    
            private void webBrowser_LoadCompleted(object sender, System.Windows.Navigation.NavigationEventArgs e)
            {
                if (e.Uri.AbsoluteUri.Contains("code="))
                {
                    if (App.Current.Properties.Contains("auth_code"))
                    {
                        App.Current.Properties.Clear();
                    }
                    string auth_code = Regex.Split(e.Uri.AbsoluteUri, "code=")[1];
                    App.Current.Properties.Add("auth_code", auth_code);
                    this.Close();
                }
            }
        }
    } 
    

    Here's a link to a more lengthy explanation: http://www.codeproject.com/Articles/497199/Switch-to-SMS-Text-Event-Reminders-When-Your-Ultra#live