Saturday, February 02, 2008

When IHTMLWindow2.document throws UnauthorizedAccessException

This is basically a C# translation of one of my older articles "When IHTMLWindow2::get_document returns E_ACCESSDENIED". Some .Net people encountered difficulties to use it, so I decided to make their life easier.

The main problem is the confusion created by System.IServiceProvider .Net interface because it has the same name as the COM interface. Once this issue is passed the code translation is straightforward. Here's the interop code to declare the COM interface IServiceProvider.
// This is the COM IServiceProvider interface, not System.IServiceProvider .Net interface!
[ComImport(), ComVisible(true), Guid("6D5140C1-7436-11CE-8034-00AA006009FA"),
InterfaceTypeAttribute(ComInterfaceType.InterfaceIsIUnknown)]
public interface IServiceProvider
{
[return: MarshalAs(UnmanagedType.I4)][PreserveSig]
int QueryService(ref Guid guidService, ref Guid riid, [MarshalAs(UnmanagedType.Interface)] out object ppvObject);
}
You find here full source code of the sample assembly.

This technique was successfully implemented and tested in Twebst web automation library.

47 comments:

faulpeltz said...

works like a charm!

Абзац said...

Yeah... big thanks by Jamon

Tim said...

You rock dude. Are you available for consulting?

CodeCentrix said...

Yes, I am open to any opportunity / proposition.

Jaideep Telang said...

thats look like a very good solution.however when itreid to download that piece of code, it displays following error:

Webhost4life Application Firewall Alert


Your request triggered an alert! If you feel that you have received this page in error, please contact the administrator of this web site.

CodeCentrix said...

Sorry about that. I recently changed my hosting and I also had to change some default security settings. It shoud work now.

vikas said...

Hi this looks good but dosent work in my case i am doing something like this

for (int j = 0; j < FramesList.length; j++)
{

object index = (object)j;
IHTMLWindow2 htmlWindow = (IHTMLWindow2)FramesList.item(ref index);
IHTMLDocument2 FrameDoc = CrossFrameIE.GetDocumentFromWindow(htmlWindow);
IHTMLElementCollection ElementCollection = FrameDoc.all;
}
HtmlDocument has two frames i am able to access the first one but gets null in document for the second one the second frame is from diffrent domain and is a htpps while the parent frame is http

CodeCentrix said...

- What IE/Windows version do you use?

- Do you run the code in IE process (in a BHO or other type of IE extension) or do you run the code in a separate process?

Allen said...

Indeed sweet code.
I'm using from vb2008 and it works flawlessly
Great work

CodeCentrix said...

Thank you!

Anonymous said...

Nice one! helped me out big time

Matt Bemis said...

I am using the code and I am still getting an unauthorized exception.

Dim myWin2 As HTMLWindow2 = getFrameWindow(mydoc2, frmNo)
MsgBox("about to get frame as document")
Dim ie2 As IHTMLDocument2 = CrossFrameIE.GetDocumentFromWindow(myWin2.parent)
Dim ie3 As HTMLWindow2 = CType(myDoc.frames.item(CType(frmNo, Object)), HTMLWindow2)
frameName = ie3.name

accessing the name of ie3 returns the error.
are you still available for consulting?

CodeCentrix said...

Hello,
I need more information about your error. Please contact me on codecentrix at gmail dot com

Anonymous said...

Worked for me too, thanks! Note that you will still see the exception as the code tries the original way first.

Anonymous said...

hey ur code works gr8 but i am getting "specifed cast not valid "
in line:
mshtml.FramesCollection frames= document.frames;

CodeCentrix said...

Can you be more explicit about what is going wrong? What code are you running?

Anonymous said...

Hey if you know how to click on system tray icon in c#, please tell me. I am running a console application in which i want to right click on the system tray icon and then click on the menu displayed.
Can you help me.

Anonymous said...

best, thanks!

Anonymous said...

This works great!

I have this example code that seems to work just fine for the UnauthorizedAcccess exceptions in frames that cross domains:

private IHTMLDocument2 GetDoc()
{
IHTMLDocument2 htmlDoc = null;

try
{
htmlDoc = this.webBrowser.Document.DomDocument as IHTMLDocument2;
}
// Adapted from: http://codecentrix.blogspot.com/2008/02/when-ihtmlwindow2document-throws.html

catch(System.UnauthorizedAccessException)
{
IWebBrowser2 wb2 = this.webBrowser.ActiveXInstance as IWebBrowser2;

if(wb2 != null)
{
htmlDoc = wb2.Document as IHTMLDocument2;

if(htmlDoc != null)
{
System.Diagnostics.Debug.WriteLine("Handled exception!");
}
}
}

return htmlDoc;
}

Where this.webBrowser is a System.Windows.Forms.WebBrowser object instance.

Am I missing something? Will this be reliable too?

Thanks for your help!

CodeCentrix said...

I don't exactly understand what are you trying to accomplish. Getting the document from IWebBrowser2 object should not trigger a cross domain security exception.

Anonymous said...

Great code it works for me perfectly! Here is my code:

Dim htmlDoc As mshtml.HTMLDocument = WebBrowser1.Document.DomDocument
Dim htmlWnd As mshtml.IHTMLWindow2 = Nothing
Dim FrameDoc As mshtml.IHTMLDocument2 = Nothing
Dim fls As mshtml.HTMLEmbed = Nothing
For n As Integer = 0 To htmlDoc.frames.length - 1
htmlWnd = htmlDoc.frames.item(n)
FrameDoc = CodecentrixSample.CrossFrameIE.GetDocumentFromWindow(htmlWnd)
If FrameDoc.title.ToLower.Trim = IFrameTitle.ToLower.Trim Then
...
Exit For
End If
Next

gerald said...

Can you send me the code to create the object CodecentrixSample.CrossFrameIE.GetDocumentFromWindow from VBA

Chandru

CodeCentrix said...

I'm not a VBA expert so it will be quite difficult for me to adapt the code for VBA but I strongly recommend you to give a try to "Twebst Automation Studio" which works great for web automation/programming with VBA.

http://www.codecentrix.com/

Twebst Library can also get the document out of a frame bypassing the cross-frame security restriction.

Adrian.

gerald said...

Bascially what i need is in vb we will give reference of dll or tlb file to create object. like that is there any dll or tlb for this CodecentrixSample object. SO that i can refer witha that dll and get this object

Thanks
Chandru

vladimir said...

Thank you for the article. I have a similar problem and I cannot find a solution. I am tracing the path from an HTML element back to the parent document. So I need to do a conversion in the opposite direction - from the document to the parentWindow and than to the Frame HTML element of the parent document. How can that be done?

CodeCentrix said...

You probably need to call this method:

http://msdn.microsoft.com/en-us/library/aa741343(v=VS.85).aspx

but you still could get E_ACCESSDENIED on cross domain security restriction.

Vivek said...

thank you, it worked like a charm

haris said...

Is it possible to get this working somehow without referencing this huge mshtml liibrary ??

Thanks

CodeCentrix said...

I'm not aware of any solution without using mshtml

C...R...a...S...H said...

In C# you can do it more simple

foreach (IHTMLElement4 e in htmlDocument.getElementsByTagName("IFRAME")){
var f = e as IWebBrowser2;
var doc = f.Document as HTMLDocument;
doc.parentWindow.execScript(Script);
}

Achi said...

Hello!
Can you explain how to use CodecentrixSample.dll and Interop.SHDocVw.dll im my C# project.
I am a beginner and use Visual 2010 express.
Thanks for your sharing.

CodeCentrix said...

You can add a reference to CodecentrixSample.dll assembly or even add the .cs source code file to your project.

Achi said...

thanks for your reply.

menkaur said...

wow. this is the first thing on the topic that actually worked for me. sooo much useless shit on the net....

anyway - thanks a lot!

Apex said...

I was wondering if this works with IE9? I used your tipp for the IE capture in Greenshot, which works with cross Domain in IE8 but not with IE9. (See: http://getgreenshot.org)

Used many different ways to try to get it working, but no such luck...

I don't think I got the E_ACCESSDENIED, but something like a "no such method"... Don't have the details on me...

Did you get it working for IE9 with Twebst?

P.S.
I am working without a reference to MSHTML, making the application a lot smaller. I created all the interfaces I needed myself from using the information in oleview from the Windows Resource Kits.
This might also have some influence, but as I said with IE8 it works fine.

CodeCentrix said...

I don't exactly understand your issue. I took a quick look at your site but I couldn't see any frame/iframe.

So I think your problem is not related to cross frame security restriction.

Ravi said...

Are the guids constant?

CodeCentrix said...

Yes, Guids are usually constants.

Jhonse said...

Hello, can detailed introduced? I look for a long time of material?

Abhishek Ganguly said...

thanks

Abhishek Ganguly said...

thanks

Petar Banicevic said...
This comment has been removed by the author.
Erx.VB.NExT.Coder said...

My question is, how do you accomplish this using VB6 (Visual Basic 6.0). Why is there no mention of this being a Cross-Frame Security issue (or is that in another post)?

I am using the following to bypass cross-frame security: Edanmo's OLE interfaces & functions.

Now, this works, almost all the time on almost every single frame, however, there comes a frame or two (really rarely) where I get the Access is Denied message whenever I try to run JavaScript inside that frame using the following:

ArrayOfFrames(i).Document.parentWindow.execScript sScript, sLanguage

I get this error:
"Access is Denied -2147024891 800700005"

Now, a few days later, on the same web page, I got another two errors at different times during that day (few days after the above Access is Denied error) and the interesting thing was, the additional two errors I got that day had the exact same error numbers (both error numbers were the same) however, the error message descriptions were different. This is on the exact same line of code where i got the Access Denied message above (that being, the .execScript call inside an iframe), here are the two new errors:

' SECOND ERROR 2 DAYS LATER: 17/12/2012: Error located below, then we tried the same thing from the Immediate Window but instead running JS code "alert('hi');", and the second error displayed:
' ERROR DURING EXECUTION: Run-time error '-2147352319 (80020101)': Method 'execScript' of object 'JScriptTypeInfo' failed
' ERROR FROM IMMEDIATE WINDOW: Run-time error '-2147352319 (80020101)': Automation error

I am stumped, is there anyone smarter than me on this topic available to leave a response? I'll take anything at the moment, even sarcastic one liners. And, get this, I am supposed to be a webbrowser control expert, being a top contributor on stackOverflow under the "webbrowser-control" tag. Err, help?

Adrian Dorache said...

Hi,

Here's the C++ version and more detailed discussion: http://codecentrix.blogspot.ro/2007/10/when-ihtmlwindow2getdocument-returns.html

So the topic is about getting the document out of window when security cross restrictions are in place.

I don't know what security restrictions applies to execScript and also I don't know your exact scenario but I encounter IE functions that will work only in-process (you have to inject into IE process somehow or IE loads your DLL/BHO/toolbar or whatever extension).

I don't know about VB6. If it is possible to work with COM in VB6 then you should be able to translate the code to VB6.

However you can also write a helper COM in C++ that by-pass the security restriction and returns the HTML document and then use this COM helper in VB6.

Regards,
Adrian.

Omri Gindi said...

Amazing! Works like a charm

Omri Gindi said...

Works perfectly! thanks!

Ruwanka Madhushan said...

Yo man! Your are a life Savior..thanks for sharing your knowledge :-)