IWebBrowser2 User Agent String
Hi everyone,
I'm using an instance of an IWebBrowser2 control to embed IE in my application. Does anyone know if there's a way to change the User Agent String that gets sent when browsing to a web page? I was hoping I could append some info on it so our server knows when we're using the browser inside our application.
Thanks for any pointers!
Kelly
[394 byte] By [
Runt888] at [2007-11-19 19:41:54]

# 1 Re: IWebBrowser2 User Agent String
Doesn't the user agent part fall within the HTTP protocol scope ?
# 2 Re: IWebBrowser2 User Agent String
Doesn't the user agent part fall within the HTTP protocol scope ?
I'm not sure. If it does, will it not be able to be changed?
# 3 Re: IWebBrowser2 User Agent String
I've done more research, and I've found out that I need to implement the IOleControl interface, and handle the OnAmbientProperty function. I can query the web browser for this interface, but I haven't been able to figure out how to use my own interface. Does anyone have any ideas?
Thanks!
Kelly
# 4 Re: IWebBrowser2 User Agent String
Is there a URL you can post that has the IOleControl info you talk about ? Perhaps it will be helpful for visitors of the forum to provide a solution
# 5 Re: IWebBrowser2 User Agent String
Sure.
This (http://msdn.microsoft.com/library/default.asp?url=/library/en-us/com/html/ef85dce6-b680-4a72-9277-4cfdab27cbbc.asp) page shows the MSDN documentation form IOleControl.
This (http://www.codeproject.com/miscctrl/dhtmlui.asp?msg=314053) page shows a sample using MFC that sets the UserAgent. The code overloads the OnAmbientProperty function and checks for the dispid to be DISPID_AMBIENT_USERAGENT. However, it's derived from CFormView, which handles all the necessary COM stuff.
If someone knows how to set a custom IOleControl interface for an IWebBrowser2 control, then I'm pretty sure I can do the rest.
Kelly
EDIT:
There is also this (http://support.microsoft.com/kb/q183412/) page.
# 6 Re: IWebBrowser2 User Agent String
I think this is what you need to do:
You have hosted the webbrowser control in your app. So you have the interface pointer of it.
Write a class of your own that implements IOleClientSite and IDispatch and IUnknown.
Instatiate an object of that class.
Using the WebBrowser interface, query for IOleObject interface, and once you have this, SetClientSite passing the object that implements IOleClientSite and IDispatch.
In this class of yours, implement IOleClientSite,IUnknown, IDispatch methods.
In the Invoke implementation, check for the DISPID for useragent and set it like in the example link you posted.
For all this, refer to the walkall.cpp sample code in here (http://msdn.microsoft.com/archive/default.asp?url=/archive/en-us/samples/internet/browser/walkall/default.asp)
# 7 Re: IWebBrowser2 User Agent String
Thank you for your suggestions and the link. I will try them and let you know how they turn out.
Thanks again!
Kelly
# 8 Re: IWebBrowser2 User Agent String
Well, I ended up getting something that I think should work, but the UserAgent string doesn't ever change.
I create the WebBrowser object, query for the IOleObject, and call SetClientSite on it to set my IOleClientSite class. This object returns my Dispatch object when QueryInterface is called with IID_IDISPATCH.
Then I query for the IOleControl interface, and call OnAmbientPropertyChange( DISPID_AMBIENT_USERAGENT );
My Dispatch class looks for the UserAgent id and returns a new user agent. However, I wrote a simple JavaScript test page that shows the UserAgent, and this never seems to change.
Below are samples of the code:
Creating the WebBrowser:
if( CoCreateInstance( CLSID_WebBrowser, NULL, CLSCTX_ALL, IID_IWebBrowser2, (LPVOID*)&mWebBrowser ) == S_OK &&
mWebBrowser->QueryInterface( IID_IOleInPlaceObject, (LPVOID*)&mOleInPlaceObject ) == S_OK &&
mWebBrowser->QueryInterface( IID_IOleObject, (LPVOID*)&oleObject ) == S_OK )
{
cCHSWIN32COMInPlaceClientSite* inPlaceClientSite = new cCHSWIN32COMInPlaceClientSite( parentWindow );
oleObject->SetClientSite( inPlaceClientSite );
IOleControl* oleControl;
if( mWebBrowser->QueryInterface( IID_IOleControl, (LPVOID*)&oleControl ) == S_OK )
{
oleControl->OnAmbientPropertyChange( DISPID_AMBIENT_USERAGENT );
oleControl->Release();
}
QueryInterface for the IOleClientSite class:
HRESULT cCHSWIN32COMInPlaceClientSite::QueryInterface( REFIID iid, void** ppvObject )
{
HRESULT result = S_OK;
if( IsBadWritePtr( ppvObject, sizeof( LPVOID ) ) )
{
result = E_INVALIDARG;
}
if( result == S_OK )
{
*ppvObject = NULL;
if( iid == IID_IUnknown || iid == IID_IOleInPlaceSite )
{
AddRef();
*ppvObject = this;
return S_OK;
}
else if( iid == IID_IDispatch )
{
if( mDispatch == NULL )
{
mDispatch = new cCHSDispatch();
}
else
{
mDispatch->AddRef();
}
*ppvObject = mDispatch;
return S_OK;
}
}
return E_NOINTERFACE;
}
The Invoke function of my Dispatch class.
HRESULT cCHSDispatch::Invoke( DISPID dispIdMember, REFIID riid, LCID lcid, WORD wFlags, DISPPARAMS FAR* pDispParams,
VARIANT FAR* pVarResult, EXCEPINFO FAR* pExcepInfo, unsigned int FAR* puArgErr )
{
switch( dispIdMember )
{
case DISPID_AMBIENT_USERAGENT:
{
CComBSTR newUserAgent( "UserAgent String test" );
V_VT( pVarResult ) = VT_BSTR;
V_BSTR( pVarResult ) = newUserAgent;
return TRUE;
}
break;
}
return E_NOTIMPL;
}
Hopefully someone can see what I'm doing wrong (I'm very new at COM).
Thanks for any help!
Kelly
EDIT: I also tested this with a server based check (since somewhere I read that this doesn't change the UserAgent that is accesible from the DOM tree, so the javascript test wouldn't work). No luck with that either.
# 9 Re: IWebBrowser2 User Agent String
It seems that if you are using Navigate2 to go to a URL, then you need to pass the user agent in that method. I hope you aren't doing that.
BTW, does your Invoke get called for the useragent ?
# 10 Re: IWebBrowser2 User Agent String
I looked at Navigate2, but I didn't see where we could specify the user agent (unless it's part of the HTTP headers). However, I tested it using the Navigate function and by navigating by clicking on a link.
Yes, the UserAgent invoke gets called once at the beginning. I'm not sure if I'm supposed to be calling OnAmbientPropertyChange once, or everytime I navigate to a different page.
Kelly
# 11 Re: IWebBrowser2 User Agent String
I looked at Navigate2, but I didn't see where we could specify the user agent (unless it's part of the HTTP headers). However, I tested it using the Navigate function and by navigating by clicking on a link.
Yes.
Yes, the UserAgent invoke gets called once at the beginning. I'm not sure if I'm supposed to be calling OnAmbientPropertyChange once, or everytime I navigate to a different page.
Kelly
My guess would be as good as yours. Doesn't harm trying it.
# 12 Re: IWebBrowser2 User Agent String
I fixed the problem that I was having. When Invoke is called with DISPID_AMBIENT_USERAGENT, I was returning TRUE instead of S_OK. Oops...
Also, I was able to change the User Agent when calling Navigate by passing this:
VARIANT empty = { 0 };
VARIANT vHeaders = { 0 };
BSTR headers = SysAllocString( L"User-Agent: My Custom User Agent\r\n" );
V_VT( &vHeaders ) = VT_BSTR;
V_BSTR( &vHeaders ) = headers;
mWebBrowser->Navigate( bstrURL, &empty, &empty, &empty, &vHeaders );
Kelly
# 13 Re: IWebBrowser2 User Agent String
do you need to do this once per navigate or just once?
what is required for SysFreeString() ??
cheers
nicw
# 14 Re: IWebBrowser2 User Agent String
You should do this for every navigate call that you want to have a different user agent.
SysFreeString is declared in oleauto.h. Link to oleaut32.lib.
Kelly