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

detecting 404 using MSHTML

69 views
Skip to first unread message

Niko

unread,
Jun 1, 2004, 12:54:30 PM6/1/04
to
Hi,

using only MSHTML (i'm doing CoCreateInstance(CLSID_HTMLDocument,..)),
how can i detect navigation errors, like 404.
thanks.

Nicolas

Igor Tandetnik

unread,
Jun 1, 2004, 2:24:07 PM6/1/04
to
"Niko" <nb...@viewpoint.com> wrote in message
news:77e74af5.04060...@posting.google.com

> using only MSHTML (i'm doing CoCreateInstance(CLSID_HTMLDocument,..)),
> how can i detect navigation errors, like 404.

I have not tried it myself, but I believe MSHTML will use your
implementation of IBindHost if you provide one. If it does, then you can
use IBindHost::MonikerBindToStorage to install your own
IBindStatusCallback implementation and watch the progress of the
download operation. Don't forget to forward all method calls to
IBindStatusCallback that MSHTML provides.
--
With best wishes,
Igor Tandetnik

"For every complex problem, there is a solution that is simple, neat,
and wrong." H.L. Mencken


Niko

unread,
Jun 3, 2004, 1:36:26 PM6/3/04
to
I tried to implement IBindHost for my site object. but MSHTML never
query the interface.
I also tried to implement IServiceProvider, but here again, MSHTML
never requests IBindHost in QueryService. or if it does, it requests
it using a GUID visual doesn't recognize..

Also I tried to register my own IBindStatusCallback to the bind
context, but as soon as MSHTML start streaming it replaces it by its
own.
And then it fails if i try to replace it with mine after MSHTML
started streaming....

Any idea what object i could overload to try to get the calls and get
HTTP request status back ? i'm thinking implementing my own IBindCtx
right now.. but i'm afraid it may be more work tha needed...
thanks

"Igor Tandetnik" <itand...@mvps.org> wrote in message news:<ODDGiWAS...@TK2MSFTNGP12.phx.gbl>...

Igor Tandetnik

unread,
Jun 3, 2004, 5:31:08 PM6/3/04
to
> I tried to implement IBindHost for my site object. but MSHTML never
> query the interface.
> I also tried to implement IServiceProvider, but here again, MSHTML
> never requests IBindHost in QueryService. or if it does, it requests
> it using a GUID visual doesn't recognize..

If it is called at all, it should be called with SID_SBindHost as the
first parameter (which is the same as IID_IBindHost).

> Any idea what object i could overload to try to get the calls and get
> HTTP request status back ? i'm thinking implementing my own IBindCtx
> right now.. but i'm afraid it may be more work tha needed...

Now that I think of it, it's an interesting idea, and it just might
work. Here's how I'd go about it. Write an object implementing IBindCtx.
Internally, it creates a stock IBindCtx implementation with
CreateBindCtx, and forwards almost all method calls to it. It also
stores IBindStatusCallback object you want to use to intercept the
notifications.

The two method calls your bind context object does not forward are
RegisterObjectParam and GetObjectParam, when called with the key of
"_BSCB_Holder_". That's what RegisterBindStatusCallback uses to put an
IBindStatusCallback pointer into the bind context. So when
RegisterObjectParam is called with this key, you cache
IBindStatusCallback pointer passed as the second parameter - this is the
one supplied by MSHTML. When GetObjectParam is called with this key, you
return your IBindStatusCallback. Now you should be able to preview all
notifications. Don't forget to forward all calls to MSHTML's callback.

If you end up trying this technique out, please post the result to the
group, whether positive or negative. It could be useful, assuming it
works.


Another way is with a Passthrough APP - see

http://groups.google.com/groups?selm=u0bu6ca6DHA.2556%40TK2MSFTNGP09.phx.gbl

That's considerably more complicated.

Julien Sellgren

unread,
Jun 8, 2004, 3:16:53 AM6/8/04
to
Igor, I am in the midst of the same challenge as Niko, in that I would
like to get access to the status code returned from an
IPersistMoniker->Load() call. I implemented a custom IBindCtx object,
just as you describe in your post, which contains the stock BindCtx. I
also implemented a custom IBindStatusCallback wrapper, which forwards
calls to the one supplied by MSHTML, and gets returned by
IBindCtx::GetObjectParam().

After the call to IPersistMoniker->Load(), I successfully start
receiving calls on my custom IBindStatusCallback object. GetBindInfo()
and OnStartBinding() both get called... But then, sadly, before the
ReadyState gets to "Complete" an access violation occurs. I am
guessing that MSHTML might be QueryInterface()'ing for for some other
interface that my custom IBindStatusCallback object doesn't implement.

"Igor Tandetnik" <itand...@mvps.org> wrote in message news:<u5JxWIbS...@TK2MSFTNGP11.phx.gbl>...

Igor Tandetnik

unread,
Jun 8, 2004, 9:41:40 AM6/8/04
to
"Julien Sellgren" <juliens...@hotmail.com> wrote in message
news:725dc02e.04060...@posting.google.com

> After the call to IPersistMoniker->Load(), I successfully start
> receiving calls on my custom IBindStatusCallback object. GetBindInfo()
> and OnStartBinding() both get called... But then, sadly, before the
> ReadyState gets to "Complete" an access violation occurs. I am
> guessing that MSHTML might be QueryInterface()'ing for for some other
> interface that my custom IBindStatusCallback object doesn't implement.

Can you place a breakpoint in QueryInterface and see what you are being
queried for? Also, make sure your reference counting is correct. A crash
right before the end of operation suggests that maybe your object gets
destroyed prematurely, and the crash occurs in the last Release.

John

unread,
Jun 8, 2004, 3:16:05 PM6/8/04
to
juliens...@hotmail.com (Julien Sellgren) wrote in message news:<725dc02e.04060...@posting.google.com>...

> Igor, I am in the midst of the same challenge as Niko, in that I would
> like to get access to the status code returned from an
> IPersistMoniker->Load() call. I implemented a custom IBindCtx object,
> just as you describe in your post, which contains the stock BindCtx. I
> also implemented a custom IBindStatusCallback wrapper, which forwards
> calls to the one supplied by MSHTML, and gets returned by
> IBindCtx::GetObjectParam().
>
> After the call to IPersistMoniker->Load(), I successfully start
> receiving calls on my custom IBindStatusCallback object. GetBindInfo()
> and OnStartBinding() both get called... But then, sadly, before the
> ReadyState gets to "Complete" an access violation occurs. I am
> guessing that MSHTML might be QueryInterface()'ing for for some other
> interface that my custom IBindStatusCallback object doesn't implement.
>

I have successfully implemented this technique. Thanks to Igor, I am
now detecting status codes. A couple things to look out for....in
GetObjectParam you have to call AddRef on your IBindStatusCallback
class whenever you provide it to MSHTML because MSHTML will call
Release on it when it is done using it (this could be causing your
crash). Also, you must write your own QueryInterface in you class
that implements IBindStatusCallback. When it is called with
IID_IBindStatusCallback or IID_IUnknown, you provide a pointer to your
class (this), otherwise you forward the call to the QueryInterface
function in the IBindStatusCallback pointer that you stored when
MSHTML called RegisterObjectParam. Hope this helps. Thanks again
Igor!!!!!

Igor Tandetnik

unread,
Jun 8, 2004, 3:26:29 PM6/8/04
to
"John" <danger...@gmail.com> wrote in message
news:40c80290.0406...@posting.google.com

> Also, you must write your own QueryInterface in you class
> that implements IBindStatusCallback. When it is called with
> IID_IBindStatusCallback or IID_IUnknown, you provide a pointer to your
> class (this), otherwise you forward the call to the QueryInterface
> function in the IBindStatusCallback pointer that you stored when
> MSHTML called RegisterObjectParam.

Very, very bad idea. Don't do this. It violates COM rules. Imagine the
caller doing QI for an alternate interface (say IAuthenticate or
IHttpNegotiate) and then querying the resulting pointer back for
IBindStatusCallback. It'll get MSHTML's pointer, not yours, because
MSHTML does not know anything about your man-in-the-middle. Then it may
issue IBindStatusCallback calls bypassing your implementation.

You should implement all interfaces that are actually being queried for
in the same way - by forwarding to MSHTML's implementation. I would
expect IAuthenticate, IHttpNegotiate[2], IHttpSecurity,
IWindowForBindingUI and IServiceProvider.

Igor Tandetnik

unread,
Jun 8, 2004, 6:07:52 PM6/8/04
to
"John" <anon...@discussions.microsoft.com> wrote in message
news:1CF85B6C-2461-4AAF...@microsoft.com
> I implemented all the "public" interfaces it queried for. However,
> it quieried for IID_IBindStatusCallbackHolder and IID_IAsyncBindCtx
> which are not available in MSHTML for me to implement. If I didn't
> forward the calls to the stored IBindStatusCallback pointer, MSHTML
> would not use my IBindStatusCallback. Any ideas what I can do about
> these interfaces??? Thanks.

Curious. Never heard of these interfaces. Are you saying the whole
construct does not work if you simply don't implement them and return
E_NOINTERFACE from QI?

Igor Tandetnik

unread,
Jun 9, 2004, 9:31:42 AM6/9/04
to
"John" <anon...@discussions.microsoft.com> wrote in message
news:1CF85B6C-2461-4AAF...@microsoft.com
> I implemented all the "public" interfaces it queried for. However,
> it quieried for IID_IBindStatusCallbackHolder and IID_IAsyncBindCtx
> which are not available in MSHTML for me to implement. If I didn't
> forward the calls to the stored IBindStatusCallback pointer, MSHTML
> would not use my IBindStatusCallback. Any ideas what I can do about
> these interfaces??? Thanks.

IAsyncBindCtx has all the same methods and signatures as IBindCtx. So
you just implement IBindCtx, and return it from QI for both IID_IBindCtx
and IID_IAsyncBindCtx. IID_IAsyncBindCtx is declared in urlmon.h

IBindStatusCallbackHolder is derived from IBindStatusCallback and has no
methods above and beyond IBindStatusCallback. So again, implement
IBindStatusCallback and return it from QI for both
IID_IBindStatusCallback and IID_IBindStatusCallbackHolder. The IID for
the latter is {79eac9cc-baf9-11ce-8c82-00aa004ba90b} - it does not seem
to be defined in any public header.

I'm not exactly sure what these extra interfaces are for. They appear to
be some kind of markers - not providing any functionality, but just the
fact that the object implements them means something to the system.

Julien Sellgren

unread,
Jun 9, 2004, 2:40:54 PM6/9/04
to
John, Igor, thank you for your suggestions. I am now successfully
getting calls into all the IBindStatusCallback methods, including
OnProgress() and OnStopBinding() which is where the useful stuff seems
to live. One question to you John: You say you are able to get the
status codes (I.e 404 Page Not found etc.). Where are you getting this
from? When I call IBinding::GetBindResult() from
IBindStatusCallback::OnStopBinding(), like the MSDN documentation
would seem to indicate, I get no information returned.

Where are you getting the status codes from? Are you using
IBinding::GetBindResult() successfully? Or are you getting the info
from somewhere else?


danger...@gmail.com (John) wrote in message news:<40c80290.0406...@posting.google.com>...

Igor Tandetnik

unread,
Jun 9, 2004, 2:52:55 PM6/9/04
to
"Julien Sellgren" <juliens...@hotmail.com> wrote in message
news:725dc02e.04060...@posting.google.com

> John, Igor, thank you for your suggestions. I am now successfully
> getting calls into all the IBindStatusCallback methods, including
> OnProgress() and OnStopBinding() which is where the useful stuff seems
> to live. One question to you John: You say you are able to get the
> status codes (I.e 404 Page Not found etc.). Where are you getting this
> from? When I call IBinding::GetBindResult() from
> IBindStatusCallback::OnStopBinding(), like the MSDN documentation
> would seem to indicate, I get no information returned.

First, GetBindResult should work. May it be that you are calling it
incorrectly? Show some code.

Second, OnStopBinding comes with an error code as an HRESULT. Many of
these codes correspond to HTTP status codes. In particular, 404 would
result in INET_E_OBJECT_NOT_FOUND.

Finally, you should be able to query IBinding for IWinInetHttpInfo and
get all the information from the HTTP response. In particular, status
code can be retrieved with QueryInfo(HTTP_QUERY_STATUS_CODE |
HTTP_QUERY_FLAG_NUMBER)

Julien Sellgren

unread,
Jun 9, 2004, 6:25:17 PM6/9/04
to
Igor, thanks. Querying the IBinding pointer for the IWinInetHttpInfo
interface, then calling QueryInfo works like a charm. I am able to get
the HTTP status code as a result. Thanks also to John, who provided me
with the same explanation.

"Igor Tandetnik" <itand...@mvps.org> wrote in message news:<e1QM7LlT...@TK2MSFTNGP12.phx.gbl>...

0 new messages