dmill

I'm writing a C# IE 6 toolbar that is using MSHTML to interact with the DOM of pages loaded in IE. Everything works fine until I come across a page I need to work with that is hosted in a frameset. The frameset is hosted by domainA and the one of the frames is served from a different domain, domainB. When I try to walk the DOM of the page in the frame from domainB, I get mshtml.IHTMLFrameBase {System.UnauthorizedAccessException}. When I try using the VS debugger to step through the object tree, when I get to the frame on domainB, all the values say "Access Denied" or something similar. I've tried setting all the IE security settings to their lowest, and adding all the domains involved to trusted sites and I always get the same behavior. Is there anything I can do to get access to this frame's page programatically

Here is a snippet of the of the code I'm using to look through all the frames:

//explorer is a valid SHDocVw.WebBrowserClass

mshtml.HTMLDocument doc = (mshtml.HTMLDocument)explorer.Document;

if (doc.frames.length > 0)

{

FramesCollection framesList = doc.frames;

for (int i = 0; i < framesList.length; i++)

{

object idx = (object)i;

try

{

mshtml.HTMLWindow2 fwin =

(mshtml.HTMLWindow2)framesList.item(ref (object)idx);

mshtml.HTMLDocument fdoc = (mshtml.HTMLDocument)fwin.document;

//do something with the page.

}

}

catch (SystemException se)

{

MessageBox.Show(se.StackTrace);

}

}

}

else

{

//do something else

}

Thanks,

Dan



Re: Internet Explorer Extension Development MSHTML Access frames on different domain from Frameset

Adrian Dorache

You get the access denied exception because IE try to prevent cross frame scripting.

You can find a solution to your problem on my blog. The sample code is written in C++ and it's using ATL smart pointers but I think it's not too difficult to translate it in C#.






Re: Internet Explorer Extension Development MSHTML Access frames on different domain from Frameset

dmill

I checked out the code on your blog, and I think I understand what you're doing with the C++/ATL solution, however I'm not having much luck converting it over to C#.

From what I can tell with my rusty C++ skills you are following these steps:

1) Take the IHTMLWindow2, convert it to an IServiceProvider

2) Use the IServiceProvider->QueryService(...) method to get a IWebBrowser2

3) Use the IWebBrowser2 to access the document that was on the other domain.

Starting with 1) I tried to take my IHTMLWindow2 object and convert it into a IServiceProvider, but I get a runtime class cast exception, which I'm not surprised about since mshtml.IHTMLWindow2 doesn't implement IServiceProvider. Maybe in the interop assembly they don't implement the class exactly the same as they do in C++

Here's my attempt:

mshtml.HTMLWindow2 fwin = (mshtml.HTMLWindow2)framesList.item(ref (object)idx);

IServiceProvider prov = (IServiceProvider)fwin; //This blows up,

Type t = Type.GetType("System.Windows.Forms.WebBrowser");

System.Windows.Forms.WebBrowser brow = (System.Windows.Forms.WebBrowser)prov.GetService(t);

Any suggestions I'm pretty new to Interop and C++ windows programming so I'm not familiar with the ServiceProvider and I haven't found much good info by Googling so far.
Thanks!




Re: Internet Explorer Extension Development MSHTML Access frames on different domain from Frameset

Adrian Dorache

I quickly checked MSDN and I found the .Net interface System.IServiceProvider but I don't think it is the same as IServiceProvider COM interface. I think you need to use the COM interface rather than .Net interface.

You find the interface in servprov.h header file.






Re: Internet Explorer Extension Development MSHTML Access frames on different domain from Frameset

craig2008

were you ever able to figure this out

I'm stuck at the same point

Thanks,

Craig




Re: Internet Explorer Extension Development MSHTML Access frames on different domain from Frameset

dmill

I found this article and this article on Microsoft's site that are both essentially the same solution as was on Adrian's blog, minus the smart pointers. I ended up taking that code and creating a C++ dll and then wrapping the C++ function with a COM Interop Assembly.

Here is the C# wrapper I made for the C++ function from here:

Then I was able to call the function from my managed C# code:

public class DllWrapper

{

[DllImport("FramesetConverter.dll")]

public static extern IHTMLDocument2 frameDive(

[MarshalAs(UnmanagedType.Interface)] IHTMLDocument2 doc,

[MarshalAs(UnmanagedType.U4)] uint idx);

}

Also, a cowoker found that you can get a reference to an inner frame on a different domain as an argument to an event handler for an event that the frame throws, for example, if your external domain frame changes, you could use something like this to get a reference to it without having to use the DLL solution:

void Explorer_BeforeNavigate2(object pDisp, ref object URL, ref object Flags, ref object TargetFrameName, ref object PostData, ref object Headers, ref bool Cancel)

{

IWebBrowser2 pWB = (IWebBrowser2)pDisp;

}





Re: Internet Explorer Extension Development MSHTML Access frames on different domain from Frameset

craig2008

Thanks.

This is interesting:

void Explorer_BeforeNavigate2(object pDisp, ref object URL, ref object Flags, ref object TargetFrameName, ref object PostData, ref object Headers, ref bool Cancel)

{

IWebBrowser2 pWB = (IWebBrowser2)pDisp;

}



But i'm not quite sure how to implement it. I don't see how creating a new IWebBrowser2 object would help. Unless I made it global and was able to access the object. But even then, i'm not sure what I would do with it.



That wouldn't work anyway because the new window with the frame is opened via a link on a webpage and not a navigate command. The domain is also the same, but I still get the unauthorized exception.


I'll try the wrapper. thanks again for your help. My current work around is to just navigate to the frame url that i need. it's sloppy, but it works.





Re: Internet Explorer Extension Development MSHTML Access frames on different domain from Frameset

omrivm

Hi,

I got the same problem as you have when I¡¯m trying to access an Iframe that is not on my domain with WebBrowser in C#.

I saw that you (dmill) created an wrapper in C# for the C++ solution, but I can¡¯t find and compile the ¡°FramesetConverter.dll¡± that you use (I don¡¯t know C++ at all¡­).

Can you (or someone else Smile) please send me the dll

Thanks a lot,

Omri

omrivm@gmail.com





Re: Internet Explorer Extension Development MSHTML Access frames on different domain from Frameset

craig2008

I never did the DLL thing. Seemed like too much of a pain. Instead, I just load the frame that I want. Below is a sniplet. Some of it might not make sense because it attaches to a lot of other code.

// loop through shell windows, find matching handle and set new ieWin object
int i;
SHDocVw.ShellWindows allBrowsers = new SHDocVw.ShellWindows();
for (i = 0; i < allBrowsers.Count; i++)
{
InternetExplorer e = (InternetExplorer)allBrowsers.Item(i);
if (e.HWND == (int)hwnd)
{
ieWin = e;
af.setIE(ieWin);
// if you don't know the frame index or name, you could loop through here

HTMLDocument HTMLDoc = (HTMLDocument)ieWin.Document;
HTMLFrameBase frame = (HTMLFrameBase)HTMLDoc.getElementsByTagName("FRAME").item(null, frameIndex);
af.navigate("https://" + HTMLDoc.domain + frame.src, false, "");
//HTMLDoc = af.getDom();


found = true;
break;
}
}


This is doing a little more than needed probably for your purpose, but the HTMLFrameBase part could help.




Re: Internet Explorer Extension Development MSHTML Access frames on different domain from Frameset

omrivm

Hi,

You found the frame but you just used the ¡°src¡± that is assessable anyway. I need to access the frame document.

Thanks,

Omri





Re: Internet Explorer Extension Development MSHTML Access frames on different domain from Frameset

craig2008

You are accessing the frame document. The navigate function navigates the page to the new frame. So if you were watching IE, you would see it navigate to the frame page.

Then the dom is saved from the new page and you can access all the objects.


This is essentially what af.navigate() is doing:


object missing = Type.Missing;

// InternetExplorer ie object
ie.Navigate(url,
ref missing, ref missing, ref missing, ref missing);

while (ie.Busy)
Thread.Sleep(200);

HTMLDocument dom = (HTMLDocument)ie.Document;







Re: Internet Explorer Extension Development MSHTML Access frames on different domain from Frameset

omrivm

Hi,
I understand you solution now. but what is the "af" object that you are using
farther more if I understand correctly you need refresh the frame to get it's document, an action that I don't want to do (AJAX reasons)...


Thanks for your help,
Omri




Re: Internet Explorer Extension Development MSHTML Access frames on different domain from Frameset

craig2008

af is an object that calls functions from another class. I copied you a code sniplet.

Yes, you need to isolate the frame target url by navigating to it. Then it's no longer a frame.

The funny thing is that I had this whole problem and the domain was the same :-)

If you've got AJAX that somehow needs to be run and does something with the external frame, then you might be stuck.




Re: Internet Explorer Extension Development MSHTML Access frames on different domain from Frameset

Adrian Dorache

I translated the code in C#. You can find the code on my blog. Here's the article:

When IHTMLWindow2.document throws UnauthorizedAccessException