I'm trying to use the web browser control to open a url and get its HTML contents. You might ask why I'm not using the System.Net objects, the web pages are formatted through java scripts so the web browser control is the faster way but I can't seem to make it work. First, WebBrowser.Navigate won't fire when called. Please help.
BTW, I wrapped the web browser control from a class in a control library. Does web browser needs to be in a windows form type of assembly? I'm guessing that it has something to do with the message pump -- but I don't know completely. I also tried to house it in a form but still failed. Anyone's help is very much appreciated. I hope Jon Skeet can say something on this :).
Navigate is a method not an event, which event are you expecting to fire?
Yes the browser control expects a parent (otherwise it will have problems like this).
Since the browser control is also an STA component, it also expect a message pump (e.g. Application.Run( new FormMain() or formMain.ShowDialog()) in the current thread to raise events from the background thread.
See also
BUG: DocumentComplete Does Not Fire When WebBrowser Is Not Visible
Related
After reading Dianyang Wu article and this excellent post I managed to build a small .net app (almost a C&P from Wu source code) to automatize tests (let's call it protoTestApp). My final goal is to open a dozen small windows and in each simulate a different user interacting with a web app to stress it.
It works for some extend but after I logon on the web app (let's call it InternalTestSubject) it calls a external url (let's call it ExternalTestSubject) and injects it's content on a iFrame. This particular external url is another web app and it ill look up for the parent window to get some parameters. Opening ExternalTestSubject directly is not a option.
My problem is at my protoTestApp I want to also interact with that ExternalTestSubject (find a button by id, click it, etc) but at my CompletedEvent handler the iFrame is still empty.
The WebBrowser shows both web apps full loaded and working, so I suppose the handler is just not waiting for the iFrame content to load since it's done by a Ajax async call.
Any advice to acomplish it?
I think I explained this in the answer you linked (and in more details in another related answer). AJAX pages are non-determinustic, so there is no generic approach.
Use periodic asynchronous polling to watch the page's current HTML snapshot or DOM for changes, the linked post illustrates how to do that. You can poll the frame's content in the same way.
I can imagine the frame reports to be ready but it actually does not. For instance, the frame contains frames, you have no way to know whether all these frames are loaded by using DocumentCompleted event.
In short: Using a frame to load external stuff and do the testing is not a good approach. Even if you use a timer to check the loading status manually. But according to security considerations, you will have many problems to access the DOM.
I have two suggestions for you:
Create a WebBrowser instance and open external test subject into it. You will have a very good chance to know, whether document (and its frames) have been loaded completely. You still have the full control to access any elements of the WebBrowser or cookies or click elements or change elements.
Use 3rd tool such as Selenium as test driver.
Update 1:
As the questioner does not want any 3rd tool, I'd suggest let the internal test subject query the loading completeness of the target frame periodically. Possible code can be check document.readyState == 'complete'.
So far as I know, as the external test subject is embedded as frame, due to security consideration, you might not able to access the DOM of the frame. In other words, you cannot do mouse clicks, etc., unless you change the security settings for the Webbrowser control first.
I use a webbrowser control in my application to get data from a specific web page. This web page won't work with the older IE because it specifically checks for the IE version. So I made a registry change that allows my application to work as IE 9 and everything is ok most of the time...
The problem is when a newwindow has to be opened. It won't display anything. I guess that the newwindow is acknowledged as IE 7 and I don't know how to make it disguise itself as IE9.
I also tried the other way round. I thought that if I intercepted the newwindow url then I could just send it to IE9 or open it in another instance of a webbrowser control. But the newwindow event only allows to cancel the event. You can't get any useful information out of it.
I believe that interop services is what I need but I know nothing about them.
So I've got two questions:
(1) Can I make the newwindow identify as IE9? (and how...)
(2) How can I get the newwindow url using interop services (or anything, I wouldn't care)?
It is quite strange (from my perspective) that the WebBrowser control doesn't surface the much-more-useful NewWindow3 event.
This CodeProject article describes a remarkably simple way to make it available.
In the NewWindow event, assuming your first Wb control is named WB1 and the one you want to redirect to is WB2, do the following in your WB1 NW event.
Processed = True ' This cancels the current request.
WB2.Navigate URL ' This redirects it to the second WB2 control.
Otherwise, if you want to use the NW2 (NewWindow2) event instead of the NewWindow (NW) event, do this in the NW2 event of the WB1 control.
Set ppDisp = WB2.object ' Just swaps the objects around to redirect, don't need to issue a cancel.
Also, you can do this via BeforeNavigate2 (of WB1). But slightly different code.
Cancel = True ' Cancel Request.
WB2.Navigate2 URL ' Reissue it to WB2.
Now, as long as you control where it redirects to, you can get the new window URL easily, using WB2.LocationURL or Wb2.Document.URL if i am not mistaken.
Also, if you want to change the rendering engine to IE9 (even if IE9 is installed on your computer, WB control will use IE7 rendering engine for compatibility)... there are articles online and answers on SO (including some of my previous answers) which clarify how you can alter the registry to ensure the rendering engine used by the WB control is the same as that of the installed version (IE9), otherwise, it will always use IE7. And, if you have IE4, 5 or 6 installed on a machine, it will always use IE4 for the rendering engine. I think they update teh rendering version after ever 3-4 version changes. I'm assuming during version 10, WB control rendering version will be version 10 as well.
Let me know if you need more assistance with it and i've love to know how you got along and if this helped answer your question. All my examples are in VB6, but you can transform them easily.
Cheers.
Hello and thank you for looking.
Problem Description:
I have implemented a c# WinForm application with the browser control embedded and have implemented IInternetSecurityManager to perform the tasks we need in order to allow cross-domain access in iframes with our locally installed web pages.
All things are working as expected with IInternetSecurityManager, IOleClientSite, IDocHostShowUI and IDocHostUIHandler. In other words, we are being called by the browser control for all of our implementations.
The problem is when the web page loaded in the browser control has script that calls window.showModalDialog(): The browser control instance that is being used no longer communicates with our client site. Absolutely no QueryInterface calls or any other methods are called in any of the interfaces mentioned above.
The document in the dialog is not using our security manager implementation I am assuming because the web browser control in the dialog that IE displays is not the same one we called SetClientSite() on.
Question:
How do we talk to this new browser control? We need to be able to give the browser control in the dialog that is shown by IE, our IInternetSecurityManager implementation. But, we never get the opportunity to tell it about our client site to make the hook up, so to speak. In other words, there is no communication from IE that tells us via an interface that says, "I am a new browser control created by IE and here is my IUnknown interface. This your chance to set my client site, etc." We would be golden if there was such a notification coming from IE.
The result is two different security contexts are being used and our applicaiton fails any time we are in a dialog using an iframe, because our IInternetSecurityManager implementation is not in use.
Example Source Code:
I have chiseled away at source code to protect the innocent :) and have reduced down to something I think you can work with in its own Visual Studio 2010 solution.
Please read the ReadMe.txt file for information on the problem, repro steps, etc.
The test web pages I wrote display information and steps to guide you through the use of the sample.
Please let me know if you have questions about what I am trying to accomplish or if the sample isn’t clear enough.
Please advise. Thank you.
http://home.comcast.net/~lowrider2112/bin/TestIEHost.rar
You can override the web-browser's control method CreateWebBrowserSiteBase.
protected override WebBrowserSiteBase CreateWebBrowserSiteBase()
{
return new ExtendedWebBrowserSite(this);
}
and implement ExtendedWebBrowserSite like this:
class ExtendedWebBrowserSite : WebBrowser.WebBrowserSite,
IDocHostShowUI,
IfacesEnumsStructsClasses.IServiceProvider,
IInternetSecurityManager
...
That can call the class IInternetSecurityManager.
One option would be to create your own dialog form (in C#) with another custom-security WebBrowser control on it. Then you can call from Javascript to C# to open the form instead of using showModalDialog.
I want to make an application to intercept all UI events in all the forms of my application and to write them to a log. This data can than be used to see which controls are the most used, in what order, etc. The problem is that I want this to happen automatically, without modifying the existing classes.
I made a prototype that attaches a method to a click event for all controls in a form, but how can this be done for all forms? Reflection needs a target object when manipulating events, but only the startup form can be easily accessed.
Is there a way to hook the constructor of an object? Then I could "inject" my method in all the events of the new form. Or maybe there is another way to do this.
Thanks in advance!
You can install a message filter.
A message filter is an object that implements IMessageFilter. WinForms calls your PreFilterMessage method for every message that passes through your thread's message loop. This is enough to monitor user input across the application (and gives you the option of manipulating it).
In Windows API this is done using local hooks (you can set local mouse hook using SetWindowsHookEx function). This is the proper way to do your task. In C# you need to use P/Invoke in order to get access to SetWindowsHookEx.
One more task would be to match the HWND (windows handle) to corresponding WinForms control.
Read this article for how to do this (via WM_GETCONTROLNAME message).
Also see this question which is a duplicate of yours.
You will have to work with the Win32's API Messages, I guess.
Here's a little example under the form of tutorial.
You should be able to achieve what you want with message filters - no direct P/Invoke to Win32-APIs required!
See the help on the IMessageFilter interface for more info.
How to create a open a webpage as a popup using c# and need to run a function when the popup window is closed. my intention is to create a web login/logout and run a function after successful completion of the event
Well you've not given much away, but if I'm guessing that your architecture is ASP.NET, then you should have events on the server in your page's codebehind that can process that event. If you expand a bit on your requirements we can help you out a bit more.
Just for completeness, you should know that you can't just run C# code in a browser with html/javascript. You could run a Silverlight application but I don't think that's what you're after.
To summarise, make a web request and respond to it on the server. Popups are just webpages, so the architecture there is the same. When the request comes back, you can then run JS to close the popup and make the main browser window do something.
Personally I'd just have the main browser do the login, popups are cumbersome for users in web apps.
If you are using jQuery, I would strongly suggest using ThickBox http://jquery.com/demo/thickbox/ We use it in every single projects we do and it work very weel and it's easy to modify to have it do what you want.
You can use it to load another aspx page where your login code would reside and then pay particual attention to
function tb_remove() {
Which is called on close. This is where we added our code to return data to the page.
The short answer is, you can't. C# runs on the server and opening a popup window is a client side action. You will need to have JavaScript in your rendered markup to open the popup window when appropriate, or an anchor tag with target="_blank".
However, I agree with the other answers that popup windows are more of a pain than they are worth, they annoy users and lead to window management issues that are not always easy to solve especially when popup blockers are involved. A DOM based modal dialog is almost always a better solution.
I would go with Neil... Sorry to say this but you are exactly the type of person Jeff Atwood was talking about when he wrote this article...
http://www.codinghorror.com/blog/archives/001296.html
I would suggest you take the time to learn the difference between client and server functionality, languages and technology.
I would also suggest you listen to Neil, your usability skills also need serious work.
LOL - and if you think I'm being cruel, think how cruel you're being to your users... login in a pop up window... bah