A diligent reader, Grzegorz Aksamit, discovered a serious problem in Passthrough APP. Essentially, under IE5 only the main HTML file loaded successfully, but no associated files (images, CSS and such). To fix the issue, I had to change the design of the class factory. The new code is not backward compatible - see the sample for proper incantations to instantiate a class factory. No more than a couple lines of code should be affected.
I also improved the sample somewhat by not relying on IInternetBindInfo::GetBindString(BINDSTRING_URL) to get the request URL when logging response headers - this also failed on IE5. Now I'm caching the original URL from the request, and also following redirects by watching IInternetProtocolSink::ReportProgress(BINDSTATUS_REDIRECTING).
I'd like to thank everybody who expressed interest and support of the project. -- With best wishes, Igor Tandetnik
"For every complex problem, there is a solution that is simple, neat, and wrong." H.L. Mencken
"Igor Tandetnik" <itand...@mvps.org> wrote in message news:... > For some time now, I recommended using so called passthrough > Asynchronous Pluggable Protocol (APP) handlers to solve a certain class > of problems frequently coming up in these newsgroups. Unfortunately, I > could not point to any sample that would show how to implement one. So I > decided to put my money where my mouth is, and actually write one > myself. The result of this effort is not just a sample, but a complete > toolkit for implementing your own passthrough APPs. The code is > available here: > > http://home.nyc.rr.com/itandetnik/PassthruAPP.zip > > For now, there is no documentation beyond rather scarce comments in the > source code. I plan to comment the code better, write an article and > submit to CodeProject. Meanwhile, I thought I'd better get some feedback > from fellow newsgroup goers before I embarrass myself in front of a > larger audience :) > > The toolkit is implemented in ATL. The interesting stuff, namely the > plumbing for the protocol and protocol sink wrapper objects, is in > ProtocolImpl.h and ProtocolImpl.inl. ProtocolCF.h and ProtocolCF.inl > implement a class factory - you need one to register a temporary APP > with IInternetSession. PassthroughObject.h declares a private interface > that a class factory uses to initialize the protocol wrapper. In a grand > ATL tradition, the toolkit does not attempt to hide or wrap the > underlying interfaces' complexity in any way, it just supplies all the > necessary plumbing. You can override any method on any interface, and > you don't need to implement any methods or interfaces for which you are > happy with default functionality. In fact, with this toolkit, a fully > functional transparent do-nothing passthrough APP takes about five lines > of code. > > The rest of the files form the sample application. I provide the project > and workspace/solution files for VC6 and VC7.1. The sample registers a > passthrough APP for HTTP and HTTPS protocols. The main window hosts a > WebBrowser control. You type a URL into the address bar and hit the Go > button. The browser gets navigated, and HTTP request and responce > headers for every request, including secondary requests such as images, > frames, CSS and so on, are dumped into the edit box at the bottom. The > APP in the sample is implemented using the toolkit - see TestAPP.h and > TestAPP.cpp. > > Please feel free to use the code in any way, to modify and adapt it to > your needs, or just borrow ideas. Any comments and suggestions are > welcome. It's better to reply in the groups so others can benefit from > your thoughts, but if for some reason you don't want to, e-mails are > welcome at itand...@mvps.org. Thank you for your interest. > > > BACKGROUND > I think I'd better explain what passthrough APPs are all about. There > are several technology layers that support the download and navigation > in Internet Explorer and WebBrowser control. At the top, there is > WebBrowser itself and MSHTML object that provides HTML parsing and > rendering. The client uses such interfaces as IWebBrowser2 and > IHTMLDocument2 to communicate with these high-level objects. > > WebBrowser and MSHTML use URL Monikers library to perform actual > downloads. URLMon exposes its servives via IMoniker and IBinding > interfaces, and the client (say MSHTML) implements IBindStatusCallback > and a number of associated interfaces, e.g. IHttpNegotiate or > IAuthenticate. > > Next down is an Asynchronous Pluggable Protocol handler. An APP > encapsulates the details of a particular protocol, such as http:, file: > or res:. APP exposes its services via IInternetProtocol and several > auxilliary interfaces such as IWinInetHttpInfo. URL Moniker provides > IInternetProtocolSink and IInternetBindInfo, and also makes interfaces > implemented on its client available via IServiceProvider. > > An APP is the last COM-based layer. The next layer down is usually some > non-COM API - e.g. an HTTP handler would use WinInet, and a file: > handler would use CreateFile and ReadFile. Non-COM APIs are beyond the > scope of this work. > > Most of the time, an application hosting a WebBrowser control (or a BHO > running inside IE) uses high-level services provided by WebBrowser and > MSHTML objects. However, somethimes these services are insufficient, and > a lower-level hook is required. E.g., when downloading an HTML page, > MSHTML only provides an overall progress of the operation, the download > of a page as a whole. Sometimes you would want to recognize an HTTP > request for every individually downloaded element on a page - images, > CSS stylesheets, scripts and so on. You may want to send custom headers > to the server, or process and act upon response headers, or modify the > content before it reaches the browser (though a MIME filter is better > suited for that), or simply log individual requests for debugging, > testing or profiling purposes. High-level objects don't allow you to do > any of that. > > It would be nice to be able to hook into the communication sequence > between WebBrowser/MSHTML and URL Monikers. Unfortunately, there does > not seem to be any way to do that - at least, none that I know of. So, > we look at the next level - a communication between a URL moniker and an > APP. > > Here we get lucky. An APP is supposed to encapsulate a particular > communication protocol. Microsoft realises that new protocols may emerge > after Internet Explorer is released, and some applications may involve > custom protocols. So it provides and documents an architecture  > whereby third party developers can create and install their own protocol > handlers, and Internet Explorer can immediately start using them. Such a > protocol may be registered permanently, under a well-known registry key > (but see ) or temporarily, within a single process and only while > this process is running. > > Now, it is rarely necessary to implement a full-blown APP from scratch - > after all, how often do new protocols actually get defined? But for out > purposes, it is usefult to implement a so called passthrough APP (pAPP). > It is an object that implements both sides of URL moniker-to-APP > communication, that is, it implements both IInternetProtocol and > IInternetProtocolSink / IInternetBindInfo. We register it as a temporary > handler for a standard protocol, such as HTTP. Now whenever an HTTP > request needs to be sent, URL moniker will create an instance of our > pAPP and ask it to do the job. The pAPP then creates an instance of a > standard APP for the protocol in question (I call it a target APP, or > tAPP, but be aware that I've invented the terminology myself, it's not > widely accepted, suggestions for a better naming convention are welcome) > and acts as its client. At this point, our pAPP becomes a proverbial > man-in-the-middle. In the simplest case, any method call made by URL > Moniker on pAPP is forwarded to tAPP, and any method call made by tAPP > on pAPP is forwarded back to URL Moniker. The pAPP gets to observe, and > if desired modify, every bit of information relevant to this request > passing back and forth between the moniker and the tAPP. QED > > It's also possible to register a pAPP as a permanent handler for some > custom protocol, say myhttp: (but not for a standard one, see ). Such > a protocol can behave almost like a standard protocol, by delegating > most of the work to a target APP handler. My toolkit allows one to do > that, though frankly I don't quite see where this feature might be > useful. > >  > http://msdn.microsoft.com/workshop/networking/pluggable/pluggable.asp >  http://support.microsoft.com/?id=kb;en-us;303740 > > -- > With best wishes, > Igor Tandetnik > > "For every complex problem, there is a solution that is simple, neat, > and wrong." H.L. Mencken > >