Google Groups no longer supports new Usenet posts or subscriptions. Historical content remains viewable.
Dismiss

IAuthenticate, IServiceProvider - override WebBrowser login dialog

2,430 views
Skip to first unread message

Adar Wesley

unread,
Sep 18, 2006, 3:56:01 AM9/18/06
to
Hi All,

I have a WinForms .NET 2.0 application that hosts the WebBrowser control.
Using this WebBrowser control to access web sites that require authentication,
I would like to automate the login. I.e. I will supply the user name and
password
in code, rather than have to ask the user.

If the web site uses WinForms authentication, I can just use the DOM
interfaces and feed the username and password in the correct fields.

However, if the web site uses integrated authentication and the logged on user
is not permitted to access the site (or I want to force a different user),
the browser pops up a dialog box to prompt the user for username
and password. I would like to override this behavior.

From the research that I have done so far, I understand that I need to
implement
the IAuthenticate and IServiceProvider interfaces and somehow tell the browser
to call my implementation when authentication is needed.

Please see my implementation code below. In this implementation, the
initialization
works without returnning an error. When I navigate to a page that requires
authentication, my implementation of IServiceProvider gets
called. After returning from the call to IServiceProvider.Service I get an
Exception on my main message loop thread.
Any help in resolving this issue would be greatly appreciated.


The Exception is:
First-chance exception at 0x040050ec in BrowserHost.exe: 0xC0000005: Access
violation writing location 0x8002802b.
A first chance exception of type 'System.AccessViolationException' occurred
in System.Windows.Forms.dll
An unhandled exception of type 'System.AccessViolationException' occurred in
System.Windows.Forms.dll

Additional information: Attempted to read or write protected memory. This is
often an indication that other memory is corrupt.

The call stack is:
040050ec()
> urlmon.dll!CINet::AuthenticationRequest() + 0x7f bytes
urlmon.dll!CINet::INetAuthenticate() + 0x16 bytes
urlmon.dll!CINet::OnINetInternal() - 0x82 bytes
urlmon.dll!CINet::MyContinue() + 0x21 bytes
urlmon.dll!CINetProtImpl::Continue() + 0x13 bytes
urlmon.dll!CINetEmbdFilter::Continue() + 0x14 bytes
urlmon.dll!CINet::Continue() + 0x28 bytes
urlmon.dll!COInetProt::Continue() + 0x14 bytes
urlmon.dll!CTransaction::OnINetInternalCallback() + 0x63 bytes
urlmon.dll!CTransaction::OnINetCallback() + 0xcffd bytes
urlmon.dll!TransactionWndProc() + 0x7b28 bytes
user32.dll!_InternalCallWinProc@20() + 0x28 bytes
user32.dll!_UserCallWinProcCheckWow@32() + 0xb7 bytes
user32.dll!_DispatchMessageWorker@8() + 0xdc bytes
user32.dll!_DispatchMessageA@4() + 0xf bytes
[Managed to Native Transition]

System.Windows.Forms.dll!System.Windows.Forms.Application.ComponentManager.System.Windows.Forms.UnsafeNativeMethods.IMsoComponentManager.FPushMessageLoop(int dwComponentID, int reason = -1, int pvLoopData = 0) + 0x2f7 bytes

System.Windows.Forms.dll!System.Windows.Forms.Application.ThreadContext.RunMessageLoopInner(int
reason = -1, System.Windows.Forms.ApplicationContext context =
{System.Windows.Forms.ApplicationContext}) + 0x17d bytes

System.Windows.Forms.dll!System.Windows.Forms.Application.ThreadContext.RunMessageLoop(int
reason, System.Windows.Forms.ApplicationContext context) + 0x53 bytes

System.Windows.Forms.dll!System.Windows.Forms.Application.Run(System.Windows.Forms.Form mainForm) + 0x2e bytes

BrowserHost.exe!WesleyNS.LegacyAccess.BrowserInterface.BrowserHost.Program.Main(string[] args = {Dimensions:[0]}) Line 27 + 0xb bytes C#
mscoree.dll!__CorExeMain@0() + 0x34 bytes
kernel32.dll!_BaseProcessStart@4() + 0x23 bytes

I currently have the following implementation:

public partial class BrowserWrapper : Form
{
public BrowserWrapper()
{
InitializeComponent();
}

private BrowserRemotingProxy browserProxy = null;

private void BrowserHost_Load(object sender, EventArgs e)
{
browserProxy = new BrowserRemotingProxy(gBrowser);
}

private void btnGo_Click(object sender, EventArgs e)
{
gBrowser.Navigate(textBox1.Text);
}
}

[ComVisible(true)]
public class BrowserRemotingProxy : MarshalByRefObject, IAuthenticate,
IServiceProvider
{
public BrowserRemotingProxy(System.Windows.Forms.WebBrowser
browserControl)
{
this.browserControl = browserControl;
this.IE = browserControl.ActiveXInstance as InternetExplorer;
IServiceProvider sp = this.IE as IServiceProvider;
IProfferService theProfferService = null;
IntPtr objectProffer = IntPtr.Zero;
int cookie = -1;

sp.QueryService(ref SID_SProfferService, ref
IID_IProfferService, out objectProffer);
theProfferService = Marshal.GetObjectForIUnknown(objectProffer)
as IProfferService;
theProfferService.ProfferService(ref IID_IAuthenticate, this,
ref cookie);
}

public Guid IID_IProfferService = new
Guid("cb728b20-f786-11ce-92ad-00aa00a74cd0");
public Guid SID_SProfferService = new
Guid("cb728b20-f786-11ce-92ad-00aa00a74cd0");
public Guid IID_IAuthenticate = new
Guid("79eac9d0-baf9-11ce-8c82-00aa004ba90b");

#region IServiceProvider Members

int IServiceProvider.QueryService(ref Guid guidService, ref Guid
riid, out IntPtr ppvObject)
{
int hr = HRESULT.E_NOINTERFACE;

if (guidService == IID_IAuthenticate && riid ==
IID_IAuthenticate) {
ppvObject = Marshal.GetComInterfaceForObject(this,
typeof(IAuthenticate));
if (ppvObject != IntPtr.Zero) {
hr = HRESULT.S_OK;
}
} else {
ppvObject = IntPtr.Zero;
}

return hr;
}

#endregion

#region IAuthenticate Members

int IAuthenticate.Authenticate(ref IntPtr phwnd, out string
pszUsername, out string pszPassword)
{
phwnd = IntPtr.Zero;

pszUsername = "e6osnaa";
pszPassword = "trbg33";

return HRESULT.S_OK;
}

#endregion
private System.Windows.Forms.WebBrowser browserControl;
private InternetExplorer IE;
}

#region COM Interfaces import Declarations
public struct HRESULT
{
public const int S_OK = 0;
public const int S_FALSE = 1;
public const int E_NOTIMPL = unchecked((int)0x80004001);
public const int E_INVALIDARG = unchecked((int)0x80070057);
public const int E_NOINTERFACE = unchecked((int)0x80004002);
public const int E_FAIL = unchecked((int)0x80004005);
public const int E_UNEXPECTED = unchecked((int)0x8000FFFF);
}

#region IServiceProvider Interface
[ComVisible(true), ComImport(),
Guid("6d5140c1-7436-11ce-8034-00aa006009fa"),
InterfaceTypeAttribute(ComInterfaceType.InterfaceIsIUnknown)]
public interface IServiceProvider
{

[return: MarshalAs(UnmanagedType.I4)]
[PreserveSig]
int QueryService(
ref System.Guid guidService,
ref System.Guid riid,
out IntPtr ppvObject);
}
#endregion
#region IProfferService Interface
[ComImport, GuidAttribute("cb728b20-f786-11ce-92ad-00aa00a74cd0"),
InterfaceTypeAttribute(ComInterfaceType.InterfaceIsIUnknown),
ComVisible(true)]
public interface IProfferService
{
[return: MarshalAs(UnmanagedType.I4)]
[PreserveSig]
int ProfferService(ref Guid guidService, IServiceProvider ppvObject,
ref int cookie);

[return: MarshalAs(UnmanagedType.I4)]
[PreserveSig]
int RevokeService(int cookie);
}
#endregion
#region IAuthenticate Interface
//MIDL_INTERFACE("79eac9d0-baf9-11ce-8c82-00aa004ba90b")
//IAuthenticate : public IUnknown
//{
//public:
// virtual HRESULT STDMETHODCALLTYPE Authenticate(
// /* [out] */ HWND *phwnd,
// /* [out] */ LPWSTR *pszUsername,
// /* [out] */ LPWSTR *pszPassword) = 0;
//}
[ComVisible(true), ComImport()]
[GuidAttribute("79eac9d0-baf9-11ce-8c82-00aa004ba90b")]
public interface IAuthenticate
{
[return: MarshalAs(UnmanagedType.I4)]
[PreserveSig]
int Authenticate([In, Out] ref IntPtr phwnd,
[Out, MarshalAs(UnmanagedType.LPWStr)] out string pszUsername,
[Out, MarshalAs(UnmanagedType.LPWStr)] out string pszPassword);
}
#endregion
#endregion

---
Adar Wesley

Walter Wang [MSFT]

unread,
Sep 18, 2006, 8:57:05 PM9/18/06
to
Hi Adar,

The interface IAuthenticate can be used by the WebBrowser control to
automatically retrieve authentication information to be provided to a
website. There are a number of interfaces that are required to be
implemented on the hosting form for this interaction to properly take
place. They are IOleClientSite, IServiceProvider and IAuthenticate. The
WebBrowser object must be notified about it's host via the
IOleObject::SetClientSite() method.

I've created a working project and attached here for your reference; the
three textbox are: URL, User, Password;

For your reference, I will also post most of the code here:

#region COM Interfaces

[ComImport,
Guid("00000112-0000-0000-C000-000000000046"),
InterfaceType(ComInterfaceType.InterfaceIsIUnknown)]
public interface IOleObject
{
void SetClientSite(IOleClientSite pClientSite);
void GetClientSite(IOleClientSite ppClientSite);
void SetHostNames(object szContainerApp, object szContainerObj);
void Close(uint dwSaveOption);
void SetMoniker(uint dwWhichMoniker, object pmk);
void GetMoniker(uint dwAssign, uint dwWhichMoniker, object ppmk);
void InitFromData(IDataObject pDataObject, bool
fCreation, uint dwReserved);
void GetClipboardData(uint dwReserved, IDataObject ppDataObject);
void DoVerb(uint iVerb, uint lpmsg, object pActiveSite,
uint lindex, uint hwndParent, uint lprcPosRect);
void EnumVerbs(object ppEnumOleVerb);
void Update();
void IsUpToDate();
void GetUserClassID(uint pClsid);
void GetUserType(uint dwFormOfType, uint pszUserType);
void SetExtent(uint dwDrawAspect, uint psizel);
void GetExtent(uint dwDrawAspect, uint psizel);
void Advise(object pAdvSink, uint pdwConnection);
void Unadvise(uint dwConnection);
void EnumAdvise(object ppenumAdvise);
void GetMiscStatus(uint dwAspect, uint pdwStatus);
void SetColorScheme(object pLogpal);
}

[ComImport,
Guid("00000118-0000-0000-C000-000000000046"),
InterfaceType(ComInterfaceType.InterfaceIsIUnknown)]
public interface IOleClientSite
{
void SaveObject();
void GetMoniker(uint dwAssign, uint dwWhichMoniker, object ppmk);
void GetContainer(object ppContainer);
void ShowObject();
void OnShowWindow(bool fShow);
void RequestNewObjectLayout();
}

[ComImport,
GuidAttribute("6d5140c1-7436-11ce-8034-00aa006009fa"),
InterfaceTypeAttribute(ComInterfaceType.InterfaceIsIUnknown),
ComVisible(false)]


public interface IServiceProvider
{
[return: MarshalAs(UnmanagedType.I4)]
[PreserveSig]

int QueryService(ref Guid guidService, ref Guid riid, out IntPtr
ppvObject);
}

[ComImport, GuidAttribute("79EAC9D0-BAF9-11CE-8C82-00AA004BA90B"),
InterfaceTypeAttribute(ComInterfaceType.InterfaceIsIUnknown),
ComVisible(false)]


public interface IAuthenticate
{
[return: MarshalAs(UnmanagedType.I4)]
[PreserveSig]

int Authenticate(ref IntPtr phwnd,
ref IntPtr pszUsername,
ref IntPtr pszPassword
);
}

#endregion

public partial class Form1 : Form, IOleClientSite, IServiceProvider,
IAuthenticate
{
public static Guid IID_IAuthenticate = new
Guid("79eac9d0-baf9-11ce-8c82-00aa004ba90b");
public const int INET_E_DEFAULT_ACTION = unchecked((int)0x800C0011);
public const int S_OK = unchecked((int)0x00000000);

public Form1()
{
InitializeComponent();

}

private void button1_Click(object sender, EventArgs e)
{

string oURL = this.textBox1.Text;
webBrowser1.Navigate(oURL);
}

private void Form1_Load(object sender, EventArgs e)
{
// Navigate to about:blank first to workaround bug mentioned in
KB 320153
string oURL = "about:blank";
webBrowser1.Navigate(oURL);



object obj = webBrowser1.ActiveXInstance;
IOleObject oc = obj as IOleObject;
oc.SetClientSite(this as IOleClientSite);

}

#region IOleClientSite Members

public void SaveObject()
{
// TODO: Add Form1.SaveObject implementation
}

public void GetMoniker(uint dwAssign, uint dwWhichMoniker, object
ppmk)
{
// TODO: Add Form1.GetMoniker implementation
}

public void GetContainer(object ppContainer)
{
ppContainer = this;
}

public void ShowObject()
{
// TODO: Add Form1.ShowObject implementation
}

public void OnShowWindow(bool fShow)
{
// TODO: Add Form1.OnShowWindow implementation
}

public void RequestNewObjectLayout()
{
// TODO: Add Form1.RequestNewObjectLayout implementation
}

#endregion

#region IServiceProvider Members

public int QueryService(ref Guid guidService, ref Guid riid, out
IntPtr ppvObject)
{
int nRet = guidService.CompareTo(IID_IAuthenticate); // Zero
returned if the compared objects are equal
if (nRet == 0)
{
nRet = riid.CompareTo(IID_IAuthenticate); // Zero
returned if the compared objects are equal
if (nRet == 0)
{
ppvObject = Marshal.GetComInterfaceForObject(this,
typeof(IAuthenticate));
return S_OK;
}
}
ppvObject = new IntPtr();
return INET_E_DEFAULT_ACTION;
}

#endregion

#region IAuthenticate Members

public int Authenticate(ref IntPtr phwnd, ref IntPtr pszUsername,
ref IntPtr pszPassword)
{
IntPtr sUser = Marshal.StringToCoTaskMemAuto(textBox2.Text);
IntPtr sPassword = Marshal.StringToCoTaskMemAuto(textBox3.Text);

pszUsername = sUser;
pszPassword = sPassword;
return S_OK;
}

#endregion
}

Please reply to let me know whether or not this works for you and answers
your question. Thank you.

By the way, regarding the other post which you're working with my colleague
Linda, please also tell us whether or not you need further information.

Sincerely,
Walter Wang (waw...@online.microsoft.com, remove 'online.')
Microsoft Online Community Support

==================================================
Get notification to my posts through email? Please refer to
http://msdn.microsoft.com/subscriptions/managednewsgroups/default.aspx#notif
ications. If you are using Outlook Express, please make sure you clear the
check box "Tools/Options/Read: Get 300 headers at a time" to see your reply
promptly.

Note: The MSDN Managed Newsgroup support offering is for non-urgent issues
where an initial response from the community or a Microsoft Support
Engineer within 1 business day is acceptable. Please note that each follow
up response may take approximately 2 business days as the support
professional working with you may need further investigation to reach the
most efficient resolution. The offering is not appropriate for situations
that require urgent, real-time or phone-based interactions or complex
project analysis and dump analysis issues. Issues of this nature are best
handled working with a dedicated Microsoft Support Engineer by contacting
Microsoft Customer Support Services (CSS) at
http://msdn.microsoft.com/subscriptions/support/default.aspx.
==================================================

This posting is provided "AS IS" with no warranties, and confers no rights.

Adar Wesley

unread,
Sep 19, 2006, 11:23:02 AM9/19/06
to
Hi Walter,

Thanks for your reply with a working solution. This was great.

In the past two days I also made some progress in my own research and
managed to get to a working solution by a trial and error method.

Your solution included implementing IOleClientSite, IServiceProvider and
IAuthenticate. In the solution I got to I obtained the IProfferService from
the browser control and gave the browser control a reference to my
implementation
of IServiceProvider. See my working implementation below.

Do you have any comments on when to use which of the two aproaches?
Do we loose something in your solution because we replace the default
implementation of IOleClientSite?

Also, in my trial and error path I mostly changed the import declarations of
the
COM interfaces. In my final solution the declarations are still not exactly
the same
as your declarations. Is this a problem? How can we know what is the
"correct" way to declare these COM imported interfaces?

My working solution:

public partial class BrowserWrapper : Form
{
public BrowserWrapper()
{
InitializeComponent();
}

private BrowserRemotingProxy browserProxy = null;

private void BrowserHost_Load(object sender, EventArgs e)
{

gBrowser.Navigate("about:blank");
browserProxy = new BrowserRemotingProxy(gBrowser);
}

private void btnGo_Click(object sender, EventArgs e)
{
gBrowser.Navigate(textBox1.Text);
}
}

[ComVisible(true)]
public class BrowserRemotingProxy : MarshalByRefObject, IAuthenticate,
IServiceProvider
{
public BrowserRemotingProxy(System.Windows.Forms.WebBrowser
browserControl)
{
this.browserControl = browserControl;
this.IE = browserControl.ActiveXInstance as InternetExplorer;
IServiceProvider sp = this.IE as IServiceProvider;
IProfferService theProfferService = null;
IntPtr objectProffer = IntPtr.Zero;

uint cookie = 0;

sp.QueryService(ref SID_SProfferService, ref
IID_IProfferService, out objectProffer);
theProfferService = Marshal.GetObjectForIUnknown(objectProffer)
as IProfferService;
theProfferService.ProfferService(ref IID_IAuthenticate, this,

out cookie);
}

#region IServiceProvider Members

void IServiceProvider.QueryService(ref Guid guidService, ref Guid
riid, out IntPtr ppvObject)
{
//int hr = HRESULT.E_NOINTERFACE;

if (guidService == IID_IAuthenticate && riid ==
IID_IAuthenticate) {
ppvObject = Marshal.GetComInterfaceForObject(this,

typeof(IAuthenticate)); // this as IAuthenticate; //
//if (ppvObject != null) {
// hr = HRESULT.S_OK;
//}
} else {
ppvObject = IntPtr.Zero;
}

//return hr;
}

#endregion

#region IAuthenticate Members

void IAuthenticate.Authenticate(out IntPtr phwnd, out string

pszUsername, out string pszPassword)
{
phwnd = IntPtr.Zero;

pszUsername = "e6osnaa";
pszPassword = "trbg33";
}

#endregion

private System.Windows.Forms.WebBrowser browserControl;
private InternetExplorer IE;
}

#region COM Interfaces import Declarations
public struct HRESULT
{
public const int S_OK = 0;
public const int S_FALSE = 1;
public const int E_NOTIMPL = unchecked((int)0x80004001);
public const int E_INVALIDARG = unchecked((int)0x80070057);
public const int E_NOINTERFACE = unchecked((int)0x80004002);
public const int E_FAIL = unchecked((int)0x80004005);
public const int E_UNEXPECTED = unchecked((int)0x8000FFFF);
}

#region IServiceProvider Interface

[ComImport, InterfaceType(ComInterfaceType.InterfaceIsIUnknown),
Guid("6D5140C1-7436-11CE-8034-00AA006009FA")]
public interface IServiceProvider
{
[MethodImpl(MethodImplOptions.InternalCall, MethodCodeType =
MethodCodeType.Runtime)]
void QueryService([In] ref Guid guidService, [In] ref Guid riid,
[Out] out IntPtr ppvObject);
}

#endregion
#region IProfferService Interface
[ComImport, InterfaceType(ComInterfaceType.InterfaceIsIUnknown),
Guid("CB728B20-F786-11CE-92AD-00AA00A74CD0")]
public interface IProfferService
{
[MethodImpl(MethodImplOptions.InternalCall, MethodCodeType =
MethodCodeType.Runtime)]
void ProfferService([In] ref Guid rguidService, [In,
MarshalAs(UnmanagedType.Interface)] IServiceProvider psp, out uint pdwCookie);
[MethodImpl(MethodImplOptions.InternalCall, MethodCodeType =
MethodCodeType.Runtime)]
void RevokeService([In] uint dwCookie);
}

#endregion
#region IAuthenticate Interface
//MIDL_INTERFACE("79eac9d0-baf9-11ce-8c82-00aa004ba90b")
//IAuthenticate : public IUnknown
//{
//public:
// virtual HRESULT STDMETHODCALLTYPE Authenticate(
// /* [out] */ HWND *phwnd,
// /* [out] */ LPWSTR *pszUsername,
// /* [out] */ LPWSTR *pszPassword) = 0;
//}

[ComImport, InterfaceType(ComInterfaceType.InterfaceIsIUnknown),
ComConversionLoss,
Guid("79EAC9D0-BAF9-11CE-8C82-00AA004BA90B")]
public interface IAuthenticate
{
[MethodImpl(MethodImplOptions.InternalCall, MethodCodeType =
MethodCodeType.Runtime)]
void Authenticate([Out, ComAliasName("UrlMonInterop.wireHWND")] out

IntPtr phwnd, [Out, MarshalAs(UnmanagedType.LPWStr)] out string pszUsername,
[Out, MarshalAs(UnmanagedType.LPWStr)] out string pszPassword);
}

#endregion
#endregion

---
Adar Wesley

"Walter Wang [MSFT]" wrote:

> Forgot to attach the project in previous reply. You will have to use
> Outlook Express or other NNTP reader to download the attachment

Walter Wang [MSFT]

unread,
Sep 20, 2006, 3:13:35 AM9/20/06
to
Hi Adar,

Thank you very much for sharing your solution with the community.

The ultimate goal is to make the webbrowser call our IAuthenticate
implementation. Both solution work since the browser implements various
interfaces to get the pointer. Replacing the IOleClientSite implementation
should be OK here since the default implementation isn't doing anything
special.

Regarding the COM interface declaration difference, I think you're
referring to IAuthenticate.Authenticate's parameter type. Both are ok, if
we declare as IntPtr, we need to call Marshal.StringToCoTaskMemAuto at
runtime; if we use your declaration, then we can pass the string directly.

Regards,


Walter Wang (waw...@online.microsoft.com, remove 'online.')
Microsoft Online Community Support

==================================================
When responding to posts, please "Reply to Group" via your newsreader so
that others may learn and benefit from your issue.

0 new messages