views:

4875

answers:

9

I have a program that is using the C# WebBrowser control and it needs to detect which page is loaded to determine what to do next. The program works fine on most of the employee's computers at the office, but it does not work on some.

I have determined the problem is that the documentCompleted event is not firing on those computers it does not work on.

This program does use threads to process data, and the webbrowser.navigate call is made through a delegate. But I have also changed the code to not use delegates for the navigate action with no change in the result.

I also made a separate program that has just a basic WebBrowser and debug textfield, and the DocumentCompleted event does fire when using that program.

NOTE: The computers that it is not firing on are older PCs with single core/thread processors.

I am out of ideas on this one, any help would be appreciated.

A: 

If it is a threading issue, make sure you are calling Application.DoEvents(). I've had problems with WebBrowser not working right when I failed to do that.

Erich Mirabal
When would I need to do that? After the thread is done working?
Alright, just tried that after threads complete their work. No change. Also tried running Application.DoEvents() on a 1 second timer. No Change. :(
A: 

While trying to solve this question, I originally had my WebBrowser control in a using() block, and it was disposing itself before the DocumentCompleted event could fire. Are you doing something similar, or is the WebBrowser on a form that's staying open?

Chris Doggett
A: 

I also stuck on same problem. i dont know the solution but i am sure that its not a problem of thread (i spend my much of the time for thread).

actually u cant gaurntee on web browser control. some time it works some time it just go out of fuel

A: 

I've been looking for the solution for some time and didn't succeed. In my situation the workaround is to install Visual Studio (somewhy installation of NET Framework is not enough). Then the DocumentCompleted event works fine. But it's just a workaround not the real solution.

I'd be grateful for any help.

Pavel L.
+1  A: 

@Pavel L:

The problem here is you used a web browser control from mshtml.dll but .NET framework does not include this file. The solution for this is simply copy mshtml.dll to your app dir or set 'Copy local' property of Microsoft.mshtml to True.

Sorry for my bad english :D

CodeBlock
A: 

Hi,

I need help on Webbrowser Documentcompleted event which is fired only when i click once on my main form toolbar. I think it's a thread problem but i don't know how to solve it! Please help! I hope it's related to this discussion.

I had tried to use thead to wait for event documentcompleted but may main form continue its code before browsing was totally completed...

Here is the environnement: I have one main form which contains a WebBrowser control named myBrowser. In this main form, i call Class BrowserGE like follows to read all html pages and cascaded browse from page to page.

public frmMain()
        {
            InitializeComponent();
            //retrieve Last Game imported through stored Proc
            GamesDatabaseDataSetTableAdapters.QueriesTableAdapter lastGame = new StatsBG.GamesDatabaseDataSetTableAdapters.QueriesTableAdapter();
      //Instantiate new BrowserGE
            myBrowser = new BrowserGE(mainWebBrowser, (int)lastGame.LastGameImported());
        }

private void btnBrowser_Click(object sender, EventArgs e)
        {
            //LogIn and read newgames to be imported
            Games newGames;
            newGames = myBrowser.ReadNewGames();
      ...
      ...
        }

My class used to browse is this one:

class BrowserGE
{
    public Games games; // games to be readden
    private WebBrowser myWebBrowser;
    IFormatProvider culture = new CultureInfo("en-US", true); //to read good date format
    private HtmlDocument doc; // contains innerhtml of current page
    private int _numPage; // current numver page to navigate
    private int _lastGameImported; // last game imported
    private string _currentUrl; //current url
    ReadState continueBrowse = ReadState.NotInitialized; // state of total browsing

    public enum ReadState
    {
        NotInitialized,
        ReadingError,
        Finished,
        ContinueOnNextPage
    }

    /// <summary>
    /// Constructor
    /// </summary>
    private BrowserGE()
    {
        _numPage = 0;

    myWebBrowser = new WebBrowser();
    games = new Games();
}

/// <summary>
/// Public Constructor
/// </summary>
/// <param name="mainWebBrowser">WebBrowser control linked to (for navigation)</param>
/// <param name="lastGameImported">last game imported to avoid import same games</param>
public BrowserGE(WebBrowser mainWebBrowser, int lastGameImported)
    : this()
{
    myWebBrowser = mainWebBrowser;
    myWebBrowser.DocumentCompleted += new System.Windows.Forms.WebBrowserDocumentCompletedEventHandler(myWebBrowser_DocumentCompleted);
    _lastGameImported = lastGameImported;
}

/// <summary>
/// Read html games (synchronized method to wait end of this method before continue on caller method)
/// </summary>
/// <returns>games added</returns>
[System.Runtime.CompilerServices.MethodImpl(System.Runtime.CompilerServices.MethodImplOptions.Synchronized)]
public Games ReadNewGames()
{
    Browse();
    return games;
}

/// <summary>
/// Main cascaded Browse in all pages: LogIn, page 1, page2,etc
/// </summary>
private void Browse()
{
    if (continueBrowse != ReadState.NotInitialized)
    {
        _numPage = -1;
        NextPage();
        continueBrowse = ReadState.ContinueOnNextPage;
    }
    while (continueBrowse != ReadState.Finished & continueBrowse != ReadState.ReadingError)
    {
        //myWebBrowser.Focus();
        Application.DoEvents();
       // Thread.Sleep(100);
        if (myWebBrowser.ReadyState == WebBrowserReadyState.Uninitialized & !myWebBrowser.IsBusy)
        {
            //Log in page
            myWebBrowser.Navigate(Settings.Default.UrlGELogIn);
            Application.DoEvents();
        }
            //Wait for document completed event to fill doc with innerhtml
        else if (doc != null & myWebBrowser.ReadyState == WebBrowserReadyState.Complete & !myWebBrowser.IsBusy)
        {
            if (_currentUrl == Settings.Default.UrlGELogIn)
            {
                LogInUserPassword();
            }
            else if (_currentUrl == Settings.Default.UrlMenu)
            {
                myWebBrowser.Navigate(Settings.Default.UrlGEGamesHistory);
            }
            else if (_currentUrl == Settings.Default.UrlGEGamesHistory)
            {
                //Find first form never submitted
                //Submit firt form first time only
                if (doc.Forms.Count > 0)
                {
                    if (doc.GetElementById(Settings.Default.FieldNameGameHistoryDataGrid) == null)
                    {
                        doc.Forms[doc.Forms.Count - 1].InvokeMember("submit");
                    }
                    else
                    {
                        continueBrowse = ReadPage();
                        if (continueBrowse == ReadState.ContinueOnNextPage)
                        {
                            NextPage();
                        }
                        else if (continueBrowse == ReadState.Finished)
                        {
                            if (DialogResult.Yes == MessageBox.Show("Do you want to insert these " + 12 + " new games ?", "Confirm update", MessageBoxButtons.YesNo))
                            {
                                //GamesDatabaseDataSetTableAdapters.GamesTableAdapter ga = new StatsBG.GamesDatabaseDataSetTableAdapters.GamesTableAdapter();
                                //ga.Update(GamesDatabaseDataSet.GamesDataTable());
                            }
                        }
                        else if (continueBrowse == ReadState.ReadingError)
                        {
                            MessageBox.Show("Html Reading error");
                        }
                        //Settings.Default.UrlGEGamesHistory, Settings.Default.UrlNextGameStart, Settings.Default.UrlNextGameEnd);
                    }
                }
                else
                {
                    throw new Exception("Unable to find form of html data grid!!!");
                }

            }
            else
            {
                throw new Exception("Where goes my browser?\n" + _currentUrl);
            }
        }
    }
}

/// <summary>
/// Navigate to first LogIn Page
/// </summary>
/// <param name="loginUrl">url to vaigate</param>
/// <param name="user">user name</param>
/// <param name="pwd">password</param>
private void LogIn(string loginUrl, string user, string pwd)
{
    try
    {
        myWebBrowser.Navigate(Settings.Default.UrlGELogIn);

    }
    catch (System.InvalidOperationException e)
    {
        MessageBox.Show("Error to log in" + e.Message, "LogIn");
        //throw;
    }
    catch (Exception e)
    {
        MessageBox.Show("Error to log in" + e.Message, "LogIn");
        //throw;
    }
}

/// <summary>
/// Navigate to next page
/// </summary>
private void NextPage()
{
    //Firt form already submitted, find html data grid
    _numPage++;
    myWebBrowser.Navigate(Settings.Default.UrlNextGameStart + _numPage + Settings.Default.UrlNextGameEnd);

}
/// <summary>
/// Read current html page
/// </summary>
/// <returns></returns>
private ReadState ReadPage()
{
    // List games returned

    HtmlElement htmlTable;
    HtmlElementCollection htmlRows;
    HtmlElement oneHtmlRow;
    HtmlElementCollection HtmlCells;
    int numRow = 0;

    int currentGame = int.MaxValue;
    DateTime currentDate;
    string currentOpponent;
    string currentGameType;
    byte currentDiceCube;
    float currentWin;
    float currentLoose;
    ReadState toBeContinue = ReadState.ContinueOnNextPage;

    _numPage = 0;

    if (doc != null)
    {
        htmlTable = doc.GetElementById(Settings.Default.FieldNameGameHistoryDataGrid);

        if (htmlTable != null)
        {
            numRow = 0;
            htmlRows = htmlTable.GetElementsByTagName(Settings.Default.HtmlGamesRow);
            if (htmlRows.Count > 0)
            {
                oneHtmlRow = htmlRows[numRow];
                //Browse until lastGameImported
                #region Browse until lastGameImported
                while ((oneHtmlRow != null) & (toBeContinue == ReadState.ContinueOnNextPage))
                {
                    if (numRow > 0)//Cancel First row of headers
                    {
                        HtmlCells = oneHtmlRow.GetElementsByTagName(Settings.Default.HtmlGamesColumn);
                        if (HtmlCells != null & HtmlCells.Count > 6)
                        {
                            //SessionID
                            if (currentGame==47047186)
                            {
                                MessageBox.Show(currentGame.ToString());
                            }
                            currentGame = int.Parse(HtmlCells[0].InnerText);
                            HtmlCells[0].ScrollIntoView(true);
                            //MessageBox.Show("CurrentGame=" + currentGame + "(must be > " + _lastGameImported + ") ==> " + (currentGame - _lastGameImported).ToString());
                            if (currentGame > _lastGameImported)
                            {
                                #region Write html values in games object
                                try
                                {
                                    currentDate = DateTime.Parse(HtmlCells[1].InnerText, culture, System.Globalization.DateTimeStyles.None);
                                    currentOpponent = HtmlCells[2].InnerText;
                                    currentGameType = HtmlCells[3].InnerText;
                                    byte.TryParse(HtmlCells[4].InnerText, out currentDiceCube);
                                    float.TryParse(HtmlCells[5].InnerText, out currentWin);
                                    float.TryParse(HtmlCells[6].InnerText, out currentLoose);
                                    if (null == games.Add(currentGame, currentDate, currentOpponent, currentGameType, currentDiceCube, currentWin, currentLoose))
                                    {
                                        toBeContinue = ReadState.ReadingError;
                                        throw new Exception("Error to insert game " + currentGame);
                                    }
                                }
                                catch (Exception e)
                                {

                                    throw e;
                                }
                                #endregion

                                if (numRow+1 < htmlRows.Count & numRow < Settings.Default.HtmlNumberOfGamesByPage)
                                {
                                    oneHtmlRow = htmlRows[++numRow];
                                }
                                else
                                {
                                    oneHtmlRow = null;
                                    toBeContinue = ReadState.ContinueOnNextPage;
                                }
                            }
                            else
                            {
                                oneHtmlRow = null;
                                toBeContinue = ReadState.Finished;
                            }
                        }
                        else
                        {
                            toBeContinue = ReadState.Finished;
                        }
                    }

                    else
                    {
                        oneHtmlRow = htmlRows[++numRow];
                    }
                }
                #endregion
            }
            else
            {
                toBeContinue = ReadState.ReadingError;
            }
        }
        else
        {
            toBeContinue = ReadState.ReadingError;
        }
    }
    else
    {
        toBeContinue = ReadState.ReadingError;
    }
    return (toBeContinue);
}

/// <summary>
/// Document completed event to get html content page when completly loaded
/// </summary>
/// <param name="sender">Sender</param>
/// <param name="e">Exception</param>
private void myWebBrowser_DocumentCompleted(object sender, WebBrowserDocumentCompletedEventArgs e)
{
    if (myWebBrowser.ReadyState == WebBrowserReadyState.Complete)
    {
        doc = myWebBrowser.Document;
        _currentUrl = ((WebBrowser)sender).Url.AbsoluteUri;
    }
}

/// <summary>
/// To fill user and password in login page
/// </summary>
private void LogInUserPassword()
{
    if (myWebBrowser.ReadyState == WebBrowserReadyState.Complete)
    {
        HtmlElement elt;
        //Set user name if empty
        elt = doc.GetElementById(Settings.Default.FieldnameLogInUser);
        if (elt.GetAttribute("value") == "")
        {
            elt.SetAttribute("value", Settings.Default.FieldnameLogInUserValue);
        }
        //Set Pwd if empty
        elt = doc.GetElementById(Settings.Default.FieldnameLogInPwd);
        if (elt.GetAttribute("value") == "")
        {
            elt.SetAttribute("value", Settings.Default.FieldnameLogInPwdValue);
            //Submit first form
            doc.Forms[0].InvokeMember("submit");
        }
    }
}

}

François
+1  A: 

As explained by CodeBlock, this seems to be related by the installation state of Microsoft.mshtml.dll

We've got customers where the Microsoft.mshtml.dll is not present in GAC (nor in computer), and then the WebBrowser component never fires any event.

By using Reflector in the WebBrowser class, the DocumentComplete event is raised by a subclass named WebBrowserEvent, which implement a private interface DWebBrowserEvents2.

This interface is a ComImport of {34A715A0-6587-11D0-924A-0020AFC7AC4D}, which, I suppose, is related to Microsoft.mshtml.dll.

So our solution was to install the Office 2003 Redistributable Primary Interop Assemblies, which install the DLL on Program Files then register it on the GAC.

Note : Don't pay attention to the .NET Framework 1.1 required or office required, it just copies some dlls.

Note 2 : The 2007 package seems to include the same dll.

Styx31
A: 

I've noticed that it does not fire when the webbrowser control is loaded into a Panel. No idea how to fix that yet.

Eric