La mise en œuvre nsIProtocolHandler avec Delphi
Question
Je suis en train de construire une implémentation nsIProtocolHandler en Delphi. (Je l'ai fait un IInternetProtocol avant avec succès, et que vous voulez avoir dans FireFox ce que j'ai dans Internet Explorer.) Merci le d-gecko projet, qui relie en quelque sorte la magie TInterfacedObject à la magie nsISupports, je « m capable de faire une DLL qui fournit un nsIModule lorsqu'on lui a demandé, qui fournit un nsIFactory lorsqu'on lui a demandé, ce qui fournit un de mes quand de nsIProtocolHandler demandé, qui fournit un de mes de nsIChannel / nsIHttpChannel lorsqu'on lui a demandé.
Lors du débogage en utilisant firefox.exe comme processus hôte, je peux voir ma bibliothèque se charge, NewURI est appelé trois fois, NewChannel est appelé, et je passe un objet qui implémente nsIChannel et nsIHttpChannel .
est où je suis troublé. Je ne suis pas censé appeler OnStartRequest et OnDataAvailable sur le nsIStreamListener que je reçois, jusqu'à ce que je retourne le contrôle de AsyncOpen, mais je ne semble pas obtenir le contrôle de retour dans le thread qui AsyncOpen a été appelé.
Je l'ai essayé avec le débogage d'une enveloppe en auto-gestionnaire autour d'un défaut de http (obtenu avec CreateInstanceByContractID('@mozilla.org/network/protocol;1?name=http',
...). J'enroulai aussi l'auditeur passé. Curieusement, je vois OnStartRequest et OnDataAvailable me appelé après mon enveloppe de canal meurt, dans le même fil. Mais qui appelle? Si c'est le canal http je tentais de terminer, comment faut-il survivre (dans le même fil) et comment est-elle le contrôle d'appeler l'auditeur? Je suis déconcerté. Et coincé.
J'ai essayé de contacter le développeur principal du projet d-gecko, mais on m'a donné aucune réponse.
(Aussi, quelqu'un jamais remarqué mon texte de présentation au bas de la MDC nsIProtocolHandler ?)
(Oh une chose, oui je sais « la vie serait plus simple » si je voudrais juste hériter de nsBaseChannel en C ++. Mais le point est d'ajouter un protocole gestionnaire FireFox à un noyau de projet Delphi existant.)
Mise à jour: Je l'ai fait un peu plus de lecture, il est mentionné
La solution Je ne sais pas sur le codage Mozilla, mais ici il va. Selon nsIChannel :: asyncOpen () , ouvrir ce canal de manière asynchrone. Les données
est introduit dans le flux spécifié
auditeur comme il devient disponible. le
Les méthodes d'écoute de flux sont appelés
sur le thread qui appelle asyncOpen et
ne sont pas appelés qu'après asyncOpen
résultats. Si le rendement asyncOpen
avec succès, promet le canal
appeler au moins onStartRequest et
onStopRequest. comme protocole clapoteuses, vous implémentez un objet de canal sur votre propre ou rediriger vers un objet de canal, le consommateur du canal appelle votre canal à l'aide Je ne sais pas si je comprends ce que vous entendez par « mais je ne semble pas obtenir le contrôle de retour dans le thread qui AsyncOpen a été appelé. » Le fil est créé par le consommateur de votre protocole, et il ouvre la voie. En outre de nsIChannel :: asyncOpen () : Si asyncOpen retourne avec succès, la
canal est responsable de la tenue
lui-même en vie jusqu'à ce qu'il a appelé
onStopRequest sur ou appelé un écouteur
onChannelRedirect. Depuis asyncOpen retourne le contrôle de retour, le canal lui-même a besoin de se maintenir en vie quelque part. Si vous cherchez un exemple de code, j'ai trouvé codase très utile. Voir nsIProtocolHandler
nsIChannel . L'utilisation que je suis tombé sur protocole vue source (cette mise en œuvre peut être plus, mais n'a pas d'importance). Voici le Quoi qu'il en soit, c'est une façon longue et sinueuse de demander, comment créer vous votre chaîne?
asyncOpen()
. Comme il est un appel asynchrone, l'idée est de remettre le contrôle au consommateur immédiatement, et il est supposé appeler les callbacks comme charge dans les données.
nsViewSourceHandler
implémente canal personnalisé. nsViewSourceHandler::NewChannel(nsIURI* uri, nsIChannel* *result)
{
nsresult rv;
nsViewSourceChannel* channel;
rv = nsViewSourceChannel::Create(nsnull, NS_GET_IID(nsIChannel), (void**)&channel);
if (NS_FAILED(rv)) return rv;
rv = channel->Init(uri);
if (NS_FAILED(rv)) {
NS_RELEASE(channel);
return rv;
}
*result = NS_STATIC_CAST(nsIViewSourceChannel*, channel);
return NS_OK;
}
nsViewSourceChannel
AsyncOpen de: nsViewSourceChannel::AsyncOpen(nsIStreamListener *aListener, nsISupports *ctxt)
{
NS_ENSURE_TRUE(mChannel, NS_ERROR_FAILURE);
mListener = aListener;
/*
* We want to add ourselves to the loadgroup before opening
* mChannel, since we want to make sure we're in the loadgroup
* when mChannel finishes and fires OnStopRequest()
*/
nsCOMPtr<nsILoadGroup> loadGroup;
mChannel->GetLoadGroup(getter_AddRefs(loadGroup));
if (loadGroup)
loadGroup->AddRequest(NS_STATIC_CAST(nsIViewSourceChannel*,
this), nsnull);
nsresult rv = mChannel->AsyncOpen(this, ctxt);
if (NS_FAILED(rv) && loadGroup)
loadGroup->RemoveRequest(NS_STATIC_CAST(nsIViewSourceChannel*,
this),
nsnull, rv);
if (NS_SUCCEEDED(rv)) {
mOpened = PR_TRUE;
}
return rv;
}