Benutzer mit den meisten Antworten

Frage

I am trying to implement an Asynchronous Pluggable Protocols (APP), and wants to delegate the calls to the original handler (after some logging).

I implemented the IInternetProtocol/Root and registered the APP with IInternetSession::RegisterNameSpace. The urlmon indeed calls my Start() function, but I can't find the way to call the original Start(). How can I do it?

I am familiar with APP SDK by Igor Tandetnik, but I wish to implement it by myself.

Antworten

I implemented it on my APP object. In the code above (the one with the colors) it is the CComPtr<IMyIInternetProtocolImple>
myInProt object. What do you mean "by the client", who is the client in my scenario?

The browser, or rather, UrlMon on the browser's behalf. It creates the APP, then calls its Start method passing IInternetBindInfo* as a parameter.

In order to intercept IInternetBindInfo calls, you need a separate object that implements and forwards IInternetBindInfo the same way your APP forwards IInternetProtocol et al. Then in your implementation of Start, you create that object,
and pass its IInternetBindInfo pointer to the original APP's Start. From that point, the original APP will call methods on that object, which will turn around and forward them to the original client.

Same with IInternetProtocolSink, if you need to intercept that, too. In my Passthough APP, I have the same object implement both IInternetProtocolSink and IInternetBindInfo (just for simplicity; they don't have to be bundled together).

I don't recommend that. Your APP should support aggregation. I did the same thing originally, and observed very strange behavior from UrlMon, which went away when I enabled aggregation (don't remember the specific details though - it's been a while). UrlMon
appears to assume that the APP is aggregatable.

Alle Antworten

I implemented the IInternetProtocol/Root and registered the APP with IInternetSession::RegisterNameSpace. The urlmon indeed calls
my Start() function, but I can't find the way to call the original Start(). How can I do it?

If you don't need to look at any other method calls beyond Start, return INET_E_USE_DEFAULT_PROTOCOLHANDLER. UrlMon will switch to the default handler, and yours won't be called anymore (for this request).

I am familiar with APP SDK by Igor Tandetnik, but I wish to implement it by myself.

Well, you could study mine, then implement a similar approach in yours.

I do wish to look at ALL the calls to the methods after Start, and I need to manipulate things in part of the methods, but I also need the ability to call the original implementation in some cases.

I tried to figure out how to call the original method from your code, and I understand that it is done through the m_spInternetProtocol member, that is initialized by IInternetProtocolImpl::SetTargetUnknown() with the punkTarget that is called
in CComClassFactoryProtocol::CreateInstance with ComPtr<IUnknown> spUnkTarget that is initailized in CreateInstanceTarget() with

spTargetCF is initialized in GetTargetClassFactory by using m_spTargetCF.CopyTo to init it, BUT I fail to understand how the m_spTargetCF is initialized. I know it is in CComClassFactoryProtocol::SetTargetClassFactory that is called
by CComClassFactoryProtocol::SetTargetCLSID that is called by

CMetaFactory<Factory, Protocol, FactoryComObject>::CreateInstance, but I don't understand who is calling this function, and I don't understand the flow: When this factory is called? Is this flow of initializing the m_spInternetProtocol
and creating the m_spTargetCF is happening on every URL, or once in the process? I would be happy if you can guide me on how to achieve the ability to call the original methods.

I do wish to look at ALL the calls to the methods after Start, and I need to manipulate things in part of the methods, but I also
need the ability to call the original implementation in some cases.

Then you need to do the same thing my Passthrough APP does.

I tried to figure out how to call the original method from your code, and I understand that it is done through the
m_spInternetProtocol member, that is initialized by IInternetProtocolImpl::SetTargetUnknown() with the punkTarget that is called
in CComClassFactoryProtocol::CreateInstance with ComPtr<IUnknown> spUnkTarget that is initailized in CreateInstanceTarget() with

At the end of the day, that's just calling CoCreateInstance with CLSID_HttpProtocol or CLSID_HttpSProtocol. Or, to be precise, CoGetClassObject to obtain the original class factory, followed by CreateInstance on said class factory.

spTargetCF is initialized in GetTargetClassFactory by using m_spTargetCF.CopyTo to init it, BUT I fail to understand how the
m_spTargetCF is initialized. I know it is in CComClassFactoryProtocol::SetTargetClassFactory that is called by
CComClassFactoryProtocol::SetTargetCLSID that is called by

CMetaFactory<Factory, Protocol, FactoryComObject>::CreateInstance, but I don't understand who is calling this function

The user of the toolkit does. In my sample application, this call is in CMainDlg::OnInitDialog. CMetaFactory::CreateInstance manufactures a class factory (hence "meta" - it's a factory of factories) suitable for passing to IInternetSession::RegisterNamespace.

Is this flow of initializing the m_spInternetProtocol and creating the
m_spTargetCF is happening on every URL, or once in the process?

m_spTargetCF is initialized at the point where a custom class factory (implemented in CComClassFactoryProtocol) is created (via CMetaFactory::CreateInstance) and registered with IInternetSession - usually once per process per protocol (e.g.
HTTP or HTTPS). Then, for every request, UrlMon calls CreateInstance on CComClassFactoryProtocol. This, in turn, creates an instance of the custom APP (via the normal ATL machinery, as implemented by CComClassFactory), an instance of the
original handler (via m_spTargetCF->CreateInstance), and plugs the latter into the former (via the custom APP's implementation of IPassthroughObject::SetTargetUnknown).

I don't recommend that. Your APP should support aggregation. I did the same thing originally, and observed very strange behavior from UrlMon, which went away when I enabled aggregation (don't remember the specific details though - it's been a while). UrlMon
appears to assume that the APP is aggregatable.

"all other functions" - I meant the functions of the interfaces you mentioned. But I implemented only IInternetProtocolRoot
and IInternetProtocol, I didn't understand from the msdn that I should also implement the other two, is it a must? I will implement them too, and add support for aggregation, and will update.

Can you suggest why these calls might fail sometimes when viewing a web page in IE9 that has HTML5 video? For example I'll get the errors show below if I visit http://www.beautyoftheweb.com/Experience

So far I've only seen this on web pages that have HTML5 video, and it works fine in IE8.

My factory's CreateInstance method get's called multiple times as the page loads, but three of those calls fail to create the default http handler. The video on that page fails to run so long as my add-on is enabled.

I've tried using CoCreateInstance directly, and also using separate CoGetClassObject and CreateInstance calls:

My factory's CreateInstance method get's called multiple times as the page loads, but three of those calls fail to create the default http handler.

How do you create the default handler? What error do you get?

UrlMon may sometimes call the object's methods on workers threads that have never initialized COM (yes, I know, that's against the rules; I'm just the messenger). Things like CoCreateInstance or CoGetClassObject won't work on such a thread. That is the main
reason why I cache the default APP's IClassFactory pointer - its CreateInstance method still works from "bad" threads.

You don't normally create a separate object for IInternetProtocolInfo. It's implemented on the same APP you have already created, alongside IInternetProtocolRoot et al. You just QueryInterface for it.

I saw that you used a macro of COM_INTERFACE_ENTRY_PASSTHROUGH(IInternetProtocolInfo,m_spInternetProtoco lInfo.p) but I don't
understand the macro.

This is what it does. When my object is queried for some interface for the first time, I query the original APP for the same interface. If this succeeds, I cache the resulting pointer and report success to the client. If the query on original
APP fails, I report that failure back to the client.

spTargetCF is a class factory, it implements IClassFactory. Its CreateInstance method creates a new COM object (the original APP), which in turn implements a number of interfaces, among then IInternetProtocol, IInternetProtocolRoot and
IInternetProtocolInfo.

I managed to delegate all the calls to the different interfaces I am implementing to the default handlers, and it is working well. But I have a problem with the IInternetBindInfo. I implemented it, but I see no calls to it's functions, particularly GetBindInfo.
Do you know why? Should I do anything else besides implementing it?

I managed to delegate all the calls to the different interfaces I am implementing to the default handlers, and it is working
well. But I have a problem with the IInternetBindInfo. I implemented it, but I see no calls to it's functions, particularly
GetBindInfo.

Which object have you implemented it on? It's impemented by the client, not by the APP.

I implemented it on my APP object. In the code above (the one with the colors) it is the CComPtr<IMyIInternetProtocolImple> myInProt
object. What do you mean "by the client", who is the client in my scenario?

I implemented it on my APP object. In the code above (the one with the colors) it is the CComPtr<IMyIInternetProtocolImple>
myInProt object. What do you mean "by the client", who is the client in my scenario?

The browser, or rather, UrlMon on the browser's behalf. It creates the APP, then calls its Start method passing IInternetBindInfo* as a parameter.

In order to intercept IInternetBindInfo calls, you need a separate object that implements and forwards IInternetBindInfo the same way your APP forwards IInternetProtocol et al. Then in your implementation of Start, you create that object,
and pass its IInternetBindInfo pointer to the original APP's Start. From that point, the original APP will call methods on that object, which will turn around and forward them to the original client.

Same with IInternetProtocolSink, if you need to intercept that, too. In my Passthough APP, I have the same object implement both IInternetProtocolSink and IInternetBindInfo (just for simplicity; they don't have to be bundled together).

By the way, after my basic implementation, I tried to check the issue of memory leaks when running the same flow over and over again while disabling cache and only delegating to the default handler (we talked about this in the past - Memory
leak as a result of Async Plugable Protocol not releasing instances) and found that there is a leak. I think that this proves that Microsoft has a bug in urlmon and APP connectivity, at least when replacing the http\s protocol.