Explorer thread blocked when getting property of InternetExplorer object during event - vb.net

I'm looking for help (or suggestions/leads) on the following issue.
This console app:
looks for an InternetExplorer object,
when found, creates a new ListenerExplorer object
in which an event handler is activated (TitleChange)
Now, when you run this application while an explorer (not IE, but a general explorer.exe) is active and you navigate to a folder (this triggers a TitleChange event) the explorer thread is blocked. It is not possible to navigate further in explorer until the VB app is closed.
This pause occurs in the TitleChange sub, on the line
Console.WriteLine("URL=" + objIE.LocationURL)
Getting the LocationURL property outside of the event works fine. Within the event, it blocks the explorer thread.
What caught my attention is that in Visual Studio's immediate window, on a breakpoint on the line above, i'm unable to access the same property:
?objIE.LocationURL
Evaluation requires a thread to run temporarily. Use the Watch window to perform the evaluation.
Code:
Dim objIE As SHDocVw.InternetExplorer
Sub Main()
Dim objShellWindows As SHDocVw.ShellWindows = CreateObject(“Shell.Application”).Windows
If (objShellWindows.Count > 0) Then
objIE = objShellWindows.Item(0)
AddHandler objIE.TitleChange, AddressOf TitleChange
'wait for events until a key is pressed by the user
Do
If Not (Console.ReadKey.KeyChar = "") Then Exit Do
Loop
End If
End Sub
Private Sub TitleChange(title As String)
Console.WriteLine("TitleChange: " + title) 'works fine
Console.WriteLine("URL=" + objIE.LocationURL) 'blocks the explorer thread!
End Sub
I've Googled for days, but can't fix it... Any help would be greatly appreciated! Thanks

A console application needs a message loop.
Solved by creating a Windows Forms Application project in MS Visual Studio instead of a Console Application project.

Related

UWP adding UI control to list in non-uit thread

So as i'm learning more and more stuff of UWP and XAML i bumped into two issues, one is (i think) "navigation" related and the second a threading issue. What i'm trying to achieve is simple. I have two pages, one "home" and one "Settings". On the Home page i show the connected clients as Custom_Buttons. On the Settings page i can change some settings regarding the app and Connected Clients
Navigation Issue
On my MainPage is setup all my declarations and object classes i need. When i navigate to a page i pass me (that is the MainPage) through to the page i'm loading so i can use the properties and objects in the that i declared on the MainPage. Then when i load the page i use the page event OnNavigatedTo to handle the passed MainPage and do local stuf with it. When i switch often between the pages the app crashes and opens the page app.g.i.vb and point to the following code:
#If Debug AndAlso Not DISABLE_XAML_GENERATED_BREAK_ON_UNHANDLED_EXCEPTION Then
AddHandler Me.UnhandledException,
Sub(sender As Global.System.Object, unhandledExceptionArgs As Global.Windows.UI.Xaml.UnhandledExceptionEventArgs)
If Global.System.Diagnostics.Debugger.IsAttached Then
**Here--->>>** Global.System.Diagnostics.Debugger.Break()
End If
End Sub
#End If
And the navigation code:
Private Sub ListBox_SelectionChanged(sender As Object, e As SelectionChangedEventArgs)
If Home.IsSelected AndAlso Not ScenarioFrame.CurrentSourcePageType Is GetType(Home) Then
BackButton.Visibility = Visibility.Collapsed
ScenarioFrame.Navigate(GetType(Home), Me)
ElseIf Settings.IsSelected AndAlso Not ScenarioFrame.CurrentSourcePageType Is GetType(Settings) Then
BackButton.Visibility = Visibility.Visible
ScenarioFrame.Navigate(GetType(Settings), Me)
End If
End Sub
Threading Issue
On the MainPage I declare a class i wrote called TCP_Server. This class has a StreamSocketListener that uses the event ConnectionReceived to accept new incoming clients. I then simply create a new Object that represents a UI form of the client and pass it the StreamSocket that comes in the Event Args in the sub new. In this way each object can handles it's own Read and Write directly from the StreamSocket Then i add this new object to a ObservableCollection(Of Object) which is held in the TCP_Server Class. This list is bound to the ItemsSource of a Canvas that i use on the HomePage which is not my MainPage.
Protected Overrides Sub OnNavigatedTo(e As NavigationEventArgs)
MyBase.OnNavigatedTo(e)
If ButtonsList.ItemsSource = Nothing Then ButtonsList.ItemsSource = DirectCast(e.Parameter, MainPage).TCP_Server.Clients
End Sub
When i create this new object in the ConnectionReceived i get an error System.Exception: 'The application has called an interface that has been marshalled for another thread. (Exception from HRESULT: 0x8001010E (RPC_E_WRONG_THREAD)) '. It only works when i use the Dispatcher.RunAsync
Private Async Sub TCP_Listener_ConnectionReceived(sender As StreamSocketListener, args As StreamSocketListenerConnectionReceivedEventArgs) Handles TCP_Listener.ConnectionReceived
'Check if the client already excists or not.
Dim client As Client_Button = Clients.FirstOrDefault(Function(x) x.IPaddr = args.Socket.Information.RemoteAddress.ToString)
rootPage.NotifyUser("New Client connected! : [" & args.Socket.Information.RemoteAddress.ToString & "] Total Connected clients = " & Clients.Count, NotifyType.Message)
If client Is Nothing Then
Await CoreApplication.MainView.CoreWindow.Dispatcher.RunAsync(CoreDispatcherPriority.Normal, Function()
'Create New object
Dim x As New Client_Button(args.Socket)
'Create new task that runs Async to process incomming data
Dim tsk As Task = Task.Run(Sub() x.ProcessClientAsync())
'Add to the task list so we can stop it later on
ClientTasks.Add(tsk)
'Add it to the Clients List so we can work with the objects
Clients.Add(x)
Return True
End Function)
Else
Await CoreApplication.MainView.CoreWindow.Dispatcher.RunAsync(CoreDispatcherPriority.Normal, Function()
client = Nothing
Clients.Remove(client)
'Create New object
Dim x As New Client_Button(args.Socket)
'Create new task that runs Async to process incomming data
Dim tsk As Task = Task.Run(Sub() x.ProcessClientAsync())
'Add to the task list so we can stop it later on
ClientTasks.Add(tsk)
'Add it to the Clients List so we can work with the objects
Clients.Add(x)
Return True
End Function)
End If
End Sub
For "Navigation Issue" you described here, navigation between pages several times it will crash, please try to set NavigationCacheMode of the page to Required or Enabled as follows:
Public Sub New()
Me.InitializeComponent()
Me.NavigationCacheMode = NavigationCacheMode.Required
End Sub
Details please reference remarks of Page class. If you still have issues please provide the details about the "UnhandledException" .
For "Threading Issue", using Core​Dispatcher is the correct way and this is by design. ConnectionReceived triggered in a non-UI thread, but you invoked UI thread inside this event handle, so you need Dispatcher.RunAsync. More details you can reference this similar thread.

Working with Internet Explorer Object

My goal is to create a VB application that reads and writes information to various webpages loaded in Internet explorer.
I have created a program that works exactly as I intend in VBA. I am now trying to re-implement the same programming in VB.
I have a function that looks for and returns an Internet Explorer Object where the input matches the LocationName.
Assuming the target page is loaded, I can work with it. Methods such as getElementByID() work perfectly. If the browser window is closed and reopened, and the code is run again, the results are very inconsistent. The getIE function seems to work, but when trying to use methods like document.getElementByID() a NullReferenceException is thrown.
Does anyone know if there is anything I am missing that I need to include to get the document property to update?
EDIT: I have looked over the NullReferenceException article. It hasn't helped me unfortunately. In case I was unclear in my wording, I would like to reiterate that the same bit of code yields a different result when executed the 2nd time under the same conditions (same webpage open in Internet Explorer).
On the second execution IE.locationName is retrievable but IE.Document.title is not. The problem is definitely with the Document property as far as I can tell. I am truly stumped.
Many thanks
Public Function getIE(targetTitle As String) As SHDocVw.InternetExplorer
' Create the shell application and Collection of open windows
Dim shellObj As Object = CreateObject("Shell.Application")
Dim shellWindows As SHDocVw.ShellWindows = shellObj.Windows()
getIE = Nothing
' Scan through the Collection
For I = (shellObj.Windows.Count - 1) To 0 Step -1
' If found, assign this to the function output and exit early
If InStr(shellWindows(I).LocationName, targetTitle) Then
getIE = shellWindows(I)
Debug.Print("Found: " & shellWindows(I).LocationName)
Exit For
End If
Next I
End Function
Private Sub Button1_Click(sender As Object, e As EventArgs) Handles Button1.Click
Dim IE As SHDocVw.InternetExplorer
IE = getIE("my site title")
If IE Is Nothing Then
Debug.Print("Site not open")
Exit Sub
End If
' The code always gets this far, and despite the page being found, starts throwing exceptions from here on if the window has been closed and reopened whilst my application has stayed running.
' Sample form data insertion code
IE.Document.getElementById("textbox1").value = "my value"
' Click the submit button
IE.Document.getElementById("submit").click()
' Wait for page to load
While IE.Busy
End While
IE.Document.getElementById("textbox2").value = "my 2nd value"
' done
IE = Nothing
End sub

How to press Upload button through VBA

I was searching a lot on the web and found your website very helpfull - that is why I have not posted anything yet, just reading.
However, I need your advice in the following step of my project. The porject is to automate the creation/placing of ad for selling goods.
The website is http://olx.bg/adding/
What I am failing to do through VBA is to press the blue square called "ДОБАВИ СНИМКА" which stands for "ADD PHOTO" in the form.
Once pressed a default BROWSE window opens to select the file.
Thanks in advance!
Add two references to your VBA project:
Microsoft Internet Controls
Microsoft HTML Object Library
The HTML behind the button has an id = add-files which makes it pretty easy to locate using getElementById
Here is a working example:
Sub PushAddPhotoButton()
Dim IEexp As InternetExplorer
Set IEexp = New InternetExplorer
IEexp.Visible = True
IEexp.navigate "http://olx.bg/adding/"
Do While IEexp.readyState <> 4: DoEvents: Loop
Dim photoButton As HTMLInputElement
Set photoButton = IEexp.Document.getElementById("add-files")
If (Not photoButton Is Nothing) Then
photoButton.Click
Else
MsgBox "Button not found on web page."
End If
IEexp.Quit
Set IEexp = Nothing
End Sub
If your IE security settings are on 'High' for Internet then you won't get a dialog or an error. The IE window will simply flash and then be gone.
Change to:

Reusing browser/tab in VB.net

I am using Process.Start() to open a URL and it's great for a one-time use but if opening multiple URLs it creates either a new instance of the default browser or uses a new tab. I need to use the original tab.
Suggestions?
For Internet Explorer, you will need to reference the shdocvw.dll COM component located, by default, at c:\windows\system32\shdocvw.dll. This COM component contains a ShellWindows object that you can use to determine if there is a running instance of Internet Explorer or not, like this:
Dim internetExplorerInstances As New ShellWindows()
Dim foundIE As Boolean = False
For Each ie As InternetExplorer In internetExplorerInstances
If ie.Name = "Windows Internet Explorer" Then
ie.Navigate(ur, &H800)
foundIE = True
Exit For
End If
Next
If Not foundIE Then
' Either do nothing or use Process.Start with a new browser instance
End If
For the other browsers, you are, unfortunately,out of luck, programmatically.

VBA IE automation, To do events like displaying message,etc in excel when a link in webpage is clicked

My requirement is i need to have a VBA code in excel which runs to do some action in excel when a link in webpage is clicked.For example when i click a link "login" in webpage my VBA code should press printscreen button in keyboard(like we use sendkeys).
I have been searching for this solution since two weeks over google but failed to get one.This is urgent project requirement, please save my day,thank you very much in advance.
Here's an edited version of an answer I gave to a similar question (http://stackoverflow.com/questions/12877872/possible-to-intercept-onchange-event/12927960#12927960).
Project references set for "Microsoft HTML object library" and "Microsoft internet controls"
In a class module "clsEvents":
Option Explicit
Public WithEvents href As MSHTML.HTMLAnchorElement
'Note that having defined "href" as "WithEvents", if you choose "href"
' from the left-hand dropdown at the top of the class code module
' then the right-hand dropdown will populate with events you can select
' from to create an event-handling procedure in the class
Private Function href_onclick() As Boolean
Debug.Print "link clicked"
href_onclick = False 'cancels the navigation
End Function
In a regular module:
Option Explicit
Dim evt As clsEvents
Sub Setup()
Dim IE As New InternetExplorer
Dim el2 As Object
Set evt = New clsEvents
IE.Visible = True
IE.navigate "http://www.csee.wvu.edu/~riggs/html/select_example.html"
Do While IE.Busy
Loop
Set el2 = IE.document.getElementsByTagName("a")(1)
If Not el2 Is Nothing Then
Debug.Print "setting event capture on link:" & el2.innerText
Set evt.href = el2
End If
End Sub
If you run the Setup sub and then click the "Javascript" link on the page in IE you should see output in the Immediate window of the VB editor.
Hope that helps get you started.
There is nothing native you can do inside Internet Explorer to enable this functionality.
You would need to write an ActiveX control (using C#, C++, VB6, etc.), which would perform the Excel automation.
A few useful links:
How to automate Excel from VB6
How to write an updatable ActiveX control in VB6