InternetExplorer DocumentCompleteEventHandler not firing in C# - c#

I am new to C#, I am writing code to open an IEBrowser and do some stuff once its loaded.
If you see the code in Main below
Here is my code :
public delegate void DocumentCompleteEventHandler(SHDocVw.InternetExplorer IE);
class Program{
private static string m_autoLoginFormContents = null;
private static SHDocVw.InternetExplorer m_autologinIEWindow;
static SHDocVw.DWebBrowserEvents2_DocumentCompleteEventHandler m_AutoLoginDocCompleteHandler;
private static SHDocVw.DWebBrowserEvents2_DocumentCompleteEventHandler m_documentCompleteEventHandler;
public static event DocumentCompleteEventHandler DocumentComplete;
static void Main(string[] args)
{
m_documentCompleteEventHandler = new SHDocVw.DWebBrowserEvents2_DocumentCompleteEventHandler(DocumentCompleteEventHandler);
m_autologinIEWindow = OpenIEWindowToURL("about:blank");
m_autologinIEWindow.DocumentComplete += m_AutoLoginDocCompleteHandler;
m_AutoLoginDocCompleteHandler = new SHDocVw.DWebBrowserEvents2_DocumentCompleteEventHandler(URLAutologinDocumentCompleteEventHandler);
System.Console.Read();
}
public static void URLAutologinDocumentCompleteEventHandler(object senderObject, ref object objectTwo /* not sure what this argument is for */)
{
//Something
}
private static void DocumentCompleteEventHandler(object senderObject, ref object objectTwo /* not sure what this argument is for */ )
{
//Something
}
}
The IE Window opens up with blank page as needed but the event is never fired up, ofcourse I am doing something wrong as I am super new and probably my first code in C#.

You can make the code simple and try as said below. It is working...
You can notice the document complete event handling.
Look into comments for explanation.
static void Main()
{
//DECLARE INTERNET EXPLORER OBJECT
SHDocVw.InternetExplorer m_autologinIEWindow = new SHDocVw.InternetExplorer();
//ASSOCIATE HANDLER TO DOCUMENT COMPLETE EVENT
m_autologinIEWindow.DocumentComplete += URLAutologinDocumentCompleteEventHandler;
//NAVIGATE THE URL
m_autologinIEWindow.Navigate("about:blank");
m_autologinIEWindow.AddressBar = true;
m_autologinIEWindow.Visible = true;
}
//HANDLER DEFINITION
public static void URLAutologinDocumentCompleteEventHandler(object senderObject, ref object objectTwo /* not sure what this argument is for */)
{
//Something
}

Related

Hooking IE Events in C#

I am trying to capture events from an existing IE window. In the code sample below, I am attempting to capture the mouseClick event within the browser document when a user clicks on an element, and then eventually pull back some attributes about the element being clicked.
public partial class frmBrowserElementBuilder : Form
{
InternetExplorer ie;
public frmBrowserElementBuilder()
{
InitializeComponent();
}
private void frmBrowserElementBuilder_Load(object sender, EventArgs e)
{
//create IE
ie = new InternetExplorer();
ie.Visible = true;
//handle document completed
ie.DocumentComplete += new
DWebBrowserEvents2_DocumentCompleteEventHandler(DocumentComplete);
}
public void DocumentComplete(object pDisp, ref object URL)
{
//document was loaded
//MessageBox.Show("DocumentComplete: " + URL);
//create event handler and hook onclick from IE
DHTMLEventHandler onClickHandler = new DHTMLEventHandler(ie.Document);
onClickHandler.assignedEvent += new DHTMLEvent(this.ie_onClick);
ie.Document.onclick = onClickHandler;
}
private void ie_onClick(mshtml.IHTMLEventObj e)
{
//something was clicked
MessageBox.Show(string.Format("Event Hooked {0}, Qualifier {1}", e.type, e.qualifier));
}
public delegate void DHTMLEvent(IHTMLEventObj e);
[ComVisible(true)]
public class DHTMLEventHandler
{
public DHTMLEvent assignedEvent;
private mshtml.HTMLDocument document;
public DHTMLEventHandler(mshtml.HTMLDocument doc)
{
//assign to instance of IE document
this.document = doc;
}
[DispId(0)]
public void Call()
{
//call the event
assignedEvent(this.document.parentWindow.#event); //{System.InvalidCastException: "Specified cast is not valid."}
}
}
}
The code compiles and the void Call() triggers as expected, however, the value of this.document.parentwindow is null and is throws System.InvalidCastException: Specified cast is not valid when stepping into the assignedEvent method.
When I inspect this.document, the value of parentWindow states
The function evaluation requires all threads to run.
after forcing evaluation it states:
'((mshtml.HTMLDocumentClass)this.document).parentWindow' threw an
exception of type 'System.InvalidCastException'.
Any ideas?
This is a threading issue. The Call() call happens on an MTA thread, and you can't access MSHTML from an MTA thread. There are many ways to change this, however, the most simple is to do this:
public void DocumentComplete(object pDisp, ref object URL)
{
var events = (HTMLDocumentEvents2_Event)ie.Document;
events.onclick += (evt) =>
{
MessageBox.Show(string.Format("Event Hooked {0}, Qualifier {1}", evt.type, evt.qualifier));
return false;
};
}

Catching ctrl+c event in console application (multi-threaded)

I have a main thread of a Console Application that runs few external processes this way
private static MyExternalProcess p1;
private static MyExternalProcess p2;
private static MyExternalProcess p3;
public void Main() {
p1 = new MyExternalProcess();
p2 = new MyExternalProcess();
p3 = new MyExternalProcess();
p1.startProcess();
p2.startProcess();
p3.startProcess();
}
public static void killEveryoneOnExit() {
p1.kill();
p2.kill();
p3.kill();
}
class MyExternalProcess {
private Process p;
...
public void startProces() {
// do some stuff
PlayerProcess = new Process();
....
PlayerProcess.Start();
// do some stuff
}
public void kill() {
// do some stuff
p.Kill();
}
}
What I need to do is: when the Main thread is interrupted (exit button or ctrl+c), the other processes should be killed.
How do I trigger my method killEveryoneOnExit on CTRL+C or Exit (X) button?
Based on your question there are two events you need to catch.
First there is the console close event which is explained here: "On Exit" for a Console Application
Second you want to catch control c which is explained here: How do I trap ctrl-c in a C# console app
If you put these two together with your example you get something like this:
static ConsoleEventDelegate handler;
private delegate bool ConsoleEventDelegate(int eventType);
[DllImport("kernel32.dll", SetLastError = true)]
private static extern bool SetConsoleCtrlHandler(ConsoleEventDelegate callback, bool add);
private static MyExternalProcess p1;
public static void Main()
{
Console.CancelKeyPress += delegate
{
killEveryoneOnExit();
};
handler = new ConsoleEventDelegate(ConsoleEventCallback);
SetConsoleCtrlHandler(handler, true);
p1 = new MyExternalProcess();
p1.startProcess();
}
public static void killEveryoneOnExit()
{
p1.kill();
}
static bool ConsoleEventCallback(int eventType)
{
if (eventType == 2)
{
killEveryoneOnExit();
}
return false;
}
For a working ctrl c (fun intended) paste example: http://pastebin.com/6VV4JKPY

EventListeners Not getting called with Instance created through Reflection

Apologies had a typo...have edited...
I have a weird issue I am not sure about.
In one piece of code I have a class which is called as a singleton which has an event other classes can listen to, pretty straightforward by doing something like
Client.Instance.MyEvent += new EventHandler<EventArgs>(myHandler);
So if I have a generic class:
Class MyTest {
public MyTest() {
System.Console.WriteLine("In Constructor Registering Events");
Client.Instance.MyEvent += new EventHandler<EventArgs>(myHandler);
}
private void myHandler(object sender, EventArgs arg) {
System.Console.WriteLine("Got event!");
}
}
Now if i create the class like:
MyTest mC = new MyTest ();
Client.Instance.FireEvent();
I get the expected "In Constructor Registering Events" and "Got Event"
However if i create the class through Reflection, I do not.
Type mType = typeof(MyTest);
object mT = Activator.CreateInstance(mType);
Client.Instance.FireEvent();
All i get is "In Constructor Registering Events" but i DO NOT get the event fired message. whats going on here? Am i doing something incorrectly in my reflection calls?
Thanks -
I've just tested your claim and, with the proper type, it works the same whether the object is created using new or via reflection.
The following Working Demo can be tested here
public class Program
{
public static void Main(string[] args)
{
Client.Instance.MyEvent += delegate { Console.WriteLine("MY EVENT handled from Main"); };
MyTest mt = new MyTest();
Type mType = typeof(MyTest);
object reflectedMT = Activator.CreateInstance(mType);
Client.Instance.FireEvent();
}
}
public class Client {
private Client() {}
private static Client _inst = new Client();
public static Client Instance { get { return _inst; } }
public void FireEvent() { if(MyEvent != null) MyEvent(this, EventArgs.Empty); }
public event EventHandler<EventArgs> MyEvent;
}
public class MyTest {
public MyTest() {
System.Console.WriteLine("In Constructor Registering Events");
Client.Instance.MyEvent += new EventHandler<EventArgs>(myHandler);
}
private void myHandler(object sender, EventArgs arg) {
System.Console.WriteLine("Got event!");
}
}

how to return values from one class to another?

I'm making a program that has three classes:
Output class receives data from other two classes, writes to two new strings, combines with special formatting to another string and outputs it
AidaF class has a method that returns a value(a string) every second
GmailF class has a method that returns a value(a string) every minute or so
so i tired using return string; to return the data from classes 2 and 3 to the first class but that just returns the value to the current class, not to the first class.
Here is this code I'm working on, slimmed down a lot though. but basics are there.
namespace Final
{
public class Output
{
public static void Main()
{
Console.WriteLine(gml + aida);
}
}
public class AidaF
{
private static System.Timers.Timer aTimer;
public static void AMain()
{
aTimer = new System.Timers.Timer(1000);
aTimer.Elapsed += new ElapsedEventHandler(OnTimedEvent);
aTimer.Interval = 1000;
aTimer.Enabled = true;
}
private static void OnTimedEvent(object source, ElapsedEventArgs e)
{
...
reader.ReadToFollowing("value");
aida.Append(reader.ReadElementContentAsString()).Append(",");
return aida;
...
}
}
public class GmaillF
{
private static System.Timers.Timer gTimer;
public static void GMain()
{
gTimer = new System.Timers.Timer(200000);
gTimer.Elapsed += new ElapsedEventHandler(OnTimedEvent1);
gTimer.Interval = 200000;
gTimer.Enabled = true;
}
private static void OnTimedEvent1(object source, ElapsedEventArgs e)
{
CheckMail();
}
public static string CheckMail()
{
...
gml.Append(reader.ReadElementContentAsString()).Append(",");
return gml;
...
}
}
}
You need to call the exposed static methods from the calling class in order to get this to work, so for example your main would look more like this:
public static void Main() {
Console.WriteLine(GmailF.CheckMail() + AidaF.OnTimedEvent());
}
I'm just guessing that CheckMail and OnTimedEvent are the strings you are trying to return. Both CheckMail and OnTimedEvent have to be public static strings for the above to work.

using object in multiple function

How can i use object from one function in another ?
main()
{
private void button1_click {
MyClass object = new MyClass();
object.blabla();
}
private void button2_click {
// how can i use object from button1_click ??
}
}
By storing the object out of the scope of a function.
main()
{
MyClass obj;
private void button1_click
{
obj = new MyClass();
obj.blabla();
}
private void button2_click
{
//maybe check for null etc
obj.dosomethingelse();
}
}
basically this is a more fundamental question, which can be solved as eg
class program
{
void Main(string[] args)
{
private MyClass FooInstance;
private void button1_click()
{
// TODO be defensive: check if this.FooInstance is assigned before, to not override it!
this.FooInstance = new MyClass();
this.FooInstance.blablabla();
}
private void button2_click()
{
// TODO add some null check aka make sure, that button1_click() happened before and this.FooInstance is assigned
this.FooInstance = ....;
}
}
}
you may also choose lazy-loading as an option (mentioned by Andrew Anderson)
make object as member variable of the class where functions are defined.
main()
{
private MyClass object;
private void button1_click {
object = new MyClass();

Categories

Resources