WinForms control in Internet Explorer

P

Peter Bromley

I am building a control which embeds in Internet Explorer and which
acquires other resources when loaded.

What I need to know is how to request information from IE as the ActiveX
host. The information my control needs is the URL being fetched and
rendered - eg file:\\xxx or http://site/path. My control will then
attempt to either open another file based URL or open a WebClient stream
to read a related file.

Can this be done? I can't find any documentation in MSDN.

BTW: I have my control loading fine and understand the security
requirements involved in embedding a .NET control in IE.

TIA for any relevant info.

--
If you wish to reply to me directly, my addres is spam proofed as:

pbromley at adi dot co dot nz

Or if you prefer - (e-mail address removed) :)
 
Y

Ying-Shen Yu[MSFT]

Hi Peter,

Thanks for posting in the newsgroup.

From you description, my understanding now is you would like to embed a
WebBrowser control in your WinForm app and you want to get some information
such as URL from the WebBrowser Control.

Since WebBrowser is just a wrapper for COM component ShDocVw, you may read
the document for the COM interface. You may take a look at the IWebBrowser2
Interface, I think it provided information you need. You may found the
document at this link:

http://msdn.microsoft.com/library/default.asp?url=/workshop/browser/webbrows
er/reference/ifaces/iwebbrowser2/iwebbrowser2.asp

The LocationURL property probably is probably what you want.
Also, the DWebBrowserEvent2 interface provides the event documents for what
time to read the property

http://msdn.microsoft.com/library/default.asp?url=/workshop/browser/webbrows
er/reference/ifaces/iwebbrowser2/iwebbrowser2.asp

Ofcourse WebBrowser has wrapper these events, you may find the
corresponding .NET event in the propertygrid event tab.

Does it answer your questions?
Please be free to reply this thread if you have further questions on it.
Thanks!

Best regards,

Ying-Shen Yu [MSFT]
Microsoft Online Partner Support
Get Secure! - www.microsoft.com/security

This posting is provided "AS IS" with no warranties and confers no rights.
This mail should not be replied directly, "online" should be removed before
sending.
 
G

Guest

I thought the question was just the oposite: a Windows Forms controls embedded in a web page using <OBJECT>...</OBJECT>, viewable with Internet Explorer? Or did I misunderstood?
 
P

Peter Bromley

I thought the question was just the oposite: a Windows Forms controls embedded in a web page using <OBJECT>...</OBJECT>, viewable with Internet Explorer? Or did I misunderstood?

Yes, unfortunately, I could embed a WebBrowser in my WinForms control
(and will explore that option if necessary) but I am embedding my
WinForms control using object tags.

So, to rephrase my original question: how can I find out what URL my
*parent* IE application is loading/rendering.


--
If you wish to reply to me directly, my addres is spam proofed as:

pbromley at adi dot co dot nz

Or if you prefer - (e-mail address removed) :)
 
Y

Ying-Shen Yu[MSFT]

Hi,

Sorry for the misunderstanding.

It's not easy for IE host control to get property from the host directly,
but we can
set the URL string using script.
You may try these steps
1.define a string property on your winform control
2. write a javascript set the URL to that property on page load.
like:
<script>
function addURL() {
simpleControl1.Text = window.location;
}
</script>
<body onload="addURL()">

Does it resolve your problem?
If you still have problem on it, please feel free to reply this thread.

Best regards,

Ying-Shen Yu [MSFT]
Microsoft Online Partner Support
Get Secure! - www.microsoft.com/security

This posting is provided "AS IS" with no warranties and confers no rights.
This mail should not be replied directly, "online" should be removed before
sending.
 
P

Peter Bromley

Sorry for the misunderstanding.

No problem, my original post was ambiguous on re-reading.
It's not easy for IE host control to get property from the host directly,
but we can
set the URL string using script.
You may try these steps
1.define a string property on your winform control
2. write a javascript set the URL to that property on page load.
like:
<script>
function addURL() {
simpleControl1.Text = window.location;
}
</script>
<body onload="addURL()">

Hmmm, that sounds like a workable idea - make the IE page provide the data.
Does it resolve your problem?
If you still have problem on it, please feel free to reply this thread.

Well, yes and no. My issue is - we will have little control over the
eventual content of the web pages hosting the winform control and I am
reluctant to force too many additional constraints on the use of the
control in the web page.

You say "it's not easy for IE host(ed?) control to get property from the
host directly".

Does that mean it's impossible or just hard? I would like to know how to
do it if it _is_ possible and I'm sure other developers would too. After
all it is customary and easy for an ActiveX to retrieve the relevant OLE
Container interfaces.

--
If you wish to reply to me directly, my addres is spam proofed as:

pbromley at adi dot co dot nz

Or if you prefer - (e-mail address removed) :)
 
Y

Ying-Shen Yu[MSFT]

Hi,

ok, let me explain it in more detail,
In ActiveX controls, you may get the IWebBrowser2 interface via
GetClientSite method and follow several steps. The KB article below give
the sample code on howto do this.

257717 HOWTO: Retrieve the Top-Level IWebBrowser2 Interface from an ActiveX
http://support.microsoft.com/?id=257717

However, In .NET we don't have a managed interface definition of such
interfaces, you need write the managed definition for them ( COM
interfaces: IOleClientSite, IServiceProvider etc). And the cotrol need
Unmanaged code access permission to call these functions, which is not
available to IE Host controls by default.
I found a KB article described this problem,

311299 PRB: Cannot Retrieve Top-Level IWebBrowser2 Interface from a .NET
http://support.microsoft.com/?id=311299

So, that's why I say it's not easy to get the Webrowser Location
information via Interop.

Hope it helps.
If you have anything unclear , please feel free to reply this thread.
Thanks!

Best regards,

Ying-Shen Yu [MSFT]
Microsoft Online Partner Support
Get Secure! - www.microsoft.com/security

This posting is provided "AS IS" with no warranties and confers no rights.
This mail should not be replied directly, "online" should be removed before
sending.
 
P

Peter Bromley

In ActiveX controls, you may get the IWebBrowser2 interface via
GetClientSite method and follow several steps. The KB article below give
the sample code on howto do this.

257717 HOWTO: Retrieve the Top-Level IWebBrowser2 Interface from an ActiveX
http://support.microsoft.com/?id=257717

However, In .NET we don't have a managed interface definition of such
interfaces, you need write the managed definition for them ( COM
interfaces: IOleClientSite, IServiceProvider etc). And the cotrol need
Unmanaged code access permission to call these functions, which is not
available to IE Host controls by default.
I found a KB article described this problem,

311299 PRB: Cannot Retrieve Top-Level IWebBrowser2 Interface from a .NET
http://support.microsoft.com/?id=311299

So, that's why I say it's not easy to get the Webrowser Location
information via Interop.

Soooo...

My UserControl must provide a managed definition of OLE interfaces (you
say IOleClientSite and IServiceProvider - I am thinking more along the
lines of IObjectWithSite...). I dont actually want the top level
IWebBrowser2 interface, I want the containing site's IWebBrowser2
interface in case my control is embedded in a frame set or wherever.

And my control needs unmanaged code access permission which it will have
anyway because of our design and installation requirements.

Thanks very much. I will go away and research this now.

--
If you wish to reply to me directly, my addres is spam proofed as:

pbromley at adi dot co dot nz

Or if you prefer - (e-mail address removed) :)
 
P

Peter Bromley

Soooo...

My UserControl must provide a managed definition of OLE interfaces (you
say IOleClientSite and IServiceProvider - I am thinking more along the
lines of IObjectWithSite...). I dont actually want the top level
IWebBrowser2 interface, I want the containing site's IWebBrowser2
interface in case my control is embedded in a frame set or wherever.

And my control needs unmanaged code access permission which it will have
anyway because of our design and installation requirements.

Further, from my research, it appears that .NET is implementing
IOleObject itself and is storing the IOleClientSite interface pointer
provided by IE in it's private data structures
(Control.ActiveXInstance.clientSite). If I could get access to this
member, I would be home free.

I don't suppose there is a sanctioned way to access this member (ever
hopeful).

As I see it, my alternatives are to access the already provided
IOLEClentSite interface, or tto implement IOleObject myself to capture
the SetClientSite call. And now I am on very shakey ground. 1) does .NET
implement IOleObject in a way I can override? 2) if I expose IOleObject
myself, will that interfere with the IEHost .NET control instantation
behaviour?

Wrapping IOleClientSite, etc for calling COM will be easy. It's the COM
client site I'm having trouble with.

Please help me out here. I feel stuck. I have a requirement to embed a
control in IE as part of a wider locally delivered application. The
(signed) assembly installed in the GAC and registered. The control will
be calling mostly unmanaged code anyway. The control will need to know
its IE context so it can work in statically- or internet-accessed pages.
I want to use .NET for the UI so I can leverage the Control framework. I
don't want to write an ActiveX wrapper when .NET has already done most
of the dirty work. Is there a way out?

--
If you wish to reply to me directly, my addres is spam proofed as:

pbromley at adi dot co dot nz

Or if you prefer - (e-mail address removed) :)
 
Y

Ying-Shen Yu[MSFT]

Hi,

I'm not sure if we could derive the Control class and implement this
interface without problem, one possible way is get the IOleObject interface
reference (ok, it' needs a reflection but it's a public reflection not
private) then get the ClientSite and the WebBrowser interface. Base on my
research I can get the top level browser Location property like this way,
you may change it to get
<code>
//based on Q172763 HOWTO: Retrieve the Top-Level IWebBrowser2 Interface
from an ActiveX Control
using System;
using System.ComponentModel;
using System.Windows.Forms;
using System.Drawing;
using System.Reflection;
using System.Security;
using System.Runtime.InteropServices;
using SHDocVw;


//Use strongname to apply the customized pemission set
[assembly : AssemblyKeyFile(@"c:\key.snk")]
//Q814669 PRB: Strong Named User Controls Do Not render in Internet Explorer
[assembly: System.Security.AllowPartiallyTrustedCallers]
namespace Microsoft.Samples.WinForms.Cs.SimpleControl
{

public class SimpleControl : System.Windows.Forms.Control
{

public SimpleControl() :base()
{
Button btn = new Button();
btn.Parent = this;
btn.Text = "Button1";
btn.Location = new Point(10,10);
btn.Click += new EventHandler(Btn_OnClick);
Controls.Add(btn);
}
//from shlguid.h
Guid SID_STopLevelBrowser = new Guid(0x4C96BE40, 0x915C, 0x11CF, 0x99,
0xD3, 0x00, 0xAA, 0x00, 0x4A, 0xE8, 0x37);
Guid SID_SWebBrowserApp = typeof(SHDocVw.IWebBrowserApp).GUID;
private void Btn_OnClick(object sender, EventArgs e)
{
try
{
Guid guidIServiceProvider = typeof(IServiceProvider).GUID;
Guid guidIWebBrowser2 = typeof(SHDocVw.IWebBrowser2).GUID;
object objIServiceProvider2;
object objIWebBrowser2;


Type typeIOleObject = this.GetType().GetInterface("IOleObject",true);
//call the
method on that interface
object oleClientSite = typeIOleObject.InvokeMember("GetClientSite",
BindingFlags.Instance|BindingFlags.InvokeMethod|BindingFlags.Public,
null,this,null);
IServiceProvider serviceProvider = oleClientSite as IServiceProvider;
serviceProvider.QueryService(ref SID_STopLevelBrowser,ref
guidIServiceProvider, out objIServiceProvider2);

serviceProvider = objIServiceProvider2 as IServiceProvider;
serviceProvider.QueryService(ref SID_SWebBrowserApp, ref
guidIWebBrowser2, out objIWebBrowser2);

IWebBrowser2 webBrowser = objIWebBrowser2 as IWebBrowser2;
MessageBox.Show(webBrowser.LocationURL);
}
catch(Exception ex)
{
System.Diagnostics.Debug.WriteLine(ex.ToString());
}

}
}

[
ComImport,Guid("6d5140c1-7436-11ce-8034-00aa006009fa"),
InterfaceType(ComInterfaceType.InterfaceIsIUnknown)
]
public interface IServiceProvider
{
void QueryService( ref Guid guidService, ref Guid riid,
[MarshalAs(UnmanagedType.Interface)] out object ppvObject);
}
}
</code>
Note, you still need give the ReflectionPemission and thel UnmanagedCode
Permission in order to run this sample.
Here is another KB article which might be helpful to you to find the
information you would like to get from the WebBrowser:
<INFO: Accessing the Object Model from Within an ActiveX Control>
http://support.microsoft.com/default.aspx?scid=kb;en-us;172763

Does it resolve the issue?
Let me know if you still have problem on it.

Best regards,

Ying-Shen Yu [MSFT]
Microsoft Online Partner Support
Get Secure! - www.microsoft.com/security

This posting is provided "AS IS" with no warranties and confers no rights.
This mail should not be replied directly, "online" should be removed before
sending.
 
P

Peter Bromley

Ok this looks promising. I will go away and experiment with this. It
might take a little while to see what happens with it so bear with me if
I don't reply any time soon.

Thanks very much!

I'm not sure if we could derive the Control class and implement this
interface without problem, one possible way is get the IOleObject interface
reference (ok, it' needs a reflection but it's a public reflection not
private) then get the ClientSite and the WebBrowser interface. Base on my
research I can get the top level browser Location property like this way,
you may change it to get

code snipped
Note, you still need give the ReflectionPemission and thel UnmanagedCode
Permission in order to run this sample.
Here is another KB article which might be helpful to you to find the
information you would like to get from the WebBrowser:
<INFO: Accessing the Object Model from Within an ActiveX Control>
http://support.microsoft.com/default.aspx?scid=kb;en-us;172763

--
If you wish to reply to me directly, my addres is spam proofed as:

pbromley at adi dot co dot nz

Or if you prefer - (e-mail address removed) :)
 
P

Peter Bromley

Ok this looks promising. I will go away and experiment with this. It
might take a little while to see what happens with it so bear with me if
I don't reply any time soon.

Success!!! My usercontrol can now access the LocationURL from IE and
determine which protocol to use the access it's file, etc....

Thanks very much to Ying-Shen Yu.

If anyone is interested, I have attached some C++ code which a) wraps
IServiceProvider and IWebBrowser, and b) accesses the IWebBrowser
interface from a usercontrol.

--------------------------------------
a) Wrappers
-----------

namespace MyCorp { namespace IEInterOp {

public __sealed __value class GUIDS
{
private: GUIDS() {}

private: static System::Guid gSID_STopLevelBrowser =
System::Guid("4C96BE40-915C-11CF-99D3-00AA004AE837");
private: static System::Guid gSID_SWebBrowserApp =
System::Guid("0002DF05-0000-0000-C000-000000000046");

public: static System::Guid SID_STopLevelBrowser()
{ return gSID_STopLevelBrowser; }
public: static System::Guid SID_SWebBrowserApp()
{ return gSID_SWebBrowserApp; }
};

[ ComImport,
Guid("6D5140C1-7436-11CE-8034-00AA006009FA"),
InterfaceType(ComInterfaceType::InterfaceIsIUnknown)
]
public __gc __interface IServiceProvider
{
void QueryService(System::Guid* guidService,
System::Guid* riid,
[OutAttribute, MarshalAs(UnmanagedType::IUnknown)]
System::Object** ppvObject);
};

[ ComImport,
Guid("EAB22AC1-30C1-11CF-A7EB-0000C05BAE0B"),
InterfaceType(ComInterfaceType::InterfaceIsIDispatch)
]
public __gc __interface IWebBrowser
{
void GoBack(void);
void GoForward(void);
void GoHome(void);
void GoSearch(void);
void Navigate(System::String* URL,
[MarshalAs(UnmanagedType::Struct)]
System::IntPtr Flags,
[MarshalAs(UnmanagedType::Struct)]
System::IntPtr TargetFrameName,
[MarshalAs(UnmanagedType::Struct)]
System::IntPtr PostData,
[MarshalAs(UnmanagedType::Struct)]
System::IntPtr Headers);
void Refresh(void);
void Refresh2([MarshalAs(UnmanagedType::Struct)]
System::IntPtr Level);
void Stop(void);
[MarshalAs(UnmanagedType::IDispatch)]
__property System::Object* get_Application(void);
[MarshalAs(UnmanagedType::IDispatch)]
__property System::Object* get_Parent(void);
[MarshalAs(UnmanagedType::IDispatch)]
__property System::Object* get_Container(void);
[MarshalAs(UnmanagedType::IDispatch)]
__property System::Object* get_Document(void);
__property bool get_TopLevelContainer(void);
__property System::String* get_Type(void);
__property long get_Left(void);
__property void set_Left(long Left);
__property long get_Top(void);
__property void set_Top(long Top);
__property long get_Width(void);
__property void set_Width(long Width);
__property long get_Height(void);
__property void set_Height(long Height);
__property System::String* get_LocationName(void);
__property System::String* get_LocationURL(void);
__property bool get_Busy(void);
};

-------------------------------
b) code to access the IWebBrowser interface (C++)

void TMyControl::DetermineEnvironment(void)
{
using namespace System::Reflection;

System::Type* thisType = this->GetType();

System::Type* iOleObjectType;
System::Object* oleClientSiteObj;
MyCorp::IEInterOp::IServiceProvider* serviceProvider;
System::Object* topServiceProviderObj;
MyCorp::IEInterOp::IServiceProvider* topServiceProvider;
System::Object* webBrowserObj;
MyCorp::IEInterOp::IWebBrowser* webBrowser;

try
{
iOleObjectType = thisType->GetInterface(S"IOleObject", true);

if (iOleObjectType)
{
using namespace System::Reflection;
oleClientSiteObj = iOleObjectType->InvokeMember(
"GetClientSite",
BindingFlags(BindingFlags::Instance |
BindingFlags::InvokeMethod |
BindingFlags::public),
0, this, 0);
}

if (oleClientSiteObj)
serviceProvider =
dynamic_cast<MyCorp::IEInterOp::IServiceProvider*>(oleClientSiteObj);
if (serviceProvider)
serviceProvider->QueryService(
&MyCorp::IEInterOp::GUIDS::SID_STopLevelBrowser(),
&__typeof(MyCorp::IEInterOp::IServiceProvider)->GUID,
&topServiceProviderObj);
if (topServiceProviderObj)
topServiceProvider =
dynamic_cast<ADI::InterOp::IServiceProvider*>(topServiceProviderObj);
if (topServiceProvider)
topServiceProvider->QueryService(
&MyCorp::IEInterOp::GUIDS::SID_SWebBrowserApp(),
&__typeof(MyCorp::IEInterOp::IWebBrowser)->GUID,
&webBrowserObj);
if (webBrowserObj)
webBrowser =
dynamic_cast<MyCorp::IEInterOp::IWebBrowser*>(webBrowserObj);
if (webBrowser)
{
mHostedByIE = true;
mBaseURL = webBrowser->get_LocationURL();
}
}
__finally
{
using namespace System::Runtime::InteropServices;
if (webBrowser) Marshal::ReleaseComObject(webBrowser);
if (webBrowserObj) Marshal::ReleaseComObject(webBrowserObj);
if (topServiceProvider)
Marshal::ReleaseComObject(topServiceProvider);
if (topServiceProviderObj)
Marshal::ReleaseComObject(topServiceProviderObj);
if (serviceProvider) Marshal::ReleaseComObject(serviceProvider);
if (oleClientSiteObj) Marshal::ReleaseComObject(oleClientSiteObj);
}
}

--
If you wish to reply to me directly, my addres is spam proofed as:

pbromley at adi dot co dot nz

Or if you prefer - (e-mail address removed) :)
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Top