Comment utiliser " WinHttp.WinHttpRequest.5.1" de manière asynchrone?
le code:
var
WinHttpReq: OleVariant;
procedure TForm1.Button1Click(Sender: TObject);
begin
WinHttpReq := CreateOleObject('WinHttp.WinHttpRequest.5.1');
WinHttpReq.Open('GET', 'http://stackoverflow.com', TRUE); // asynchronously
WinHttpReq.setRequestHeader('User-Agent', 'Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.0');
WinHttpReq.Send();
// HOW to set a callback procedure here and get the response?
end;
Note: Je ne veux pas importer mshttp.dll et utiliser TLB. Je veux l'utiliser via la liaison tardive. Je voudrais également traiter des exceptions, le cas échéant.
EDIT: J'accepte la réponse de TLama parce qu'elle me donne une bonne alternative à ce que je demandais initialement. en plus, il a une bonne source d'exemple.
Voici une très belle implémentation de Winhttprequest Wrapper avec IConnectionPoint pour les événements (le code source est joint).
3 réponses
comme Stijn l'a dit dans sa réponse, pour prévenir le retard de votre programme, utilisez les threads. IWinHttpRequest.Open
a la capacité de configuration asynchrone aussi, mais il serait très difficile d'attraper les événements et IWinHttpRequest.WaitForResponse
collerait votre programme même ainsi.
voici un exemple simple de la façon d'entrer le texte de la réponse dans la boîte de note du formulaire.
Veuillez noter que l'exemple suivant utilise le mode synchrone et que vous pouvez également modifier les valeurs de timeout en utilisant IWinHttpRequest.SetTimeouts
. Si vous voulez utiliser le mode asynchrone comme vous l'avez fait dans votre question, vous devrez attendre le résultat avec la méthode IWinHttpRequest.WaitForResponse
.
///////////////////////////////////////////////////////////////////////////////
///// WinHttpRequest threading demo unit //////////////////////////////////
///////////////////////////////////////////////////////////////////////////////
unit WinHttpRequestUnit;
interface
uses
Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms,
Dialogs, ActiveX, ComObj, StdCtrls;
type
TForm1 = class(TForm)
Memo1: TMemo;
Button1: TButton;
procedure Button1Click(Sender: TObject);
private
{ Private declarations }
public
{ Public declarations }
end;
var
Form1: TForm1;
implementation
{$R *.dfm}
///////////////////////////////////////////////////////////////////////////////
///// THTTPRequest - TThread descendant for single request ////////////////
///////////////////////////////////////////////////////////////////////////////
type
THTTPRequest = class(TThread)
private
FRequestURL: string;
FResponseText: string;
procedure Execute; override;
procedure SynchronizeResult;
public
constructor Create(const RequestURL: string);
destructor Destroy; override;
end;
///////////////////////////////////////////////////////////////////////////////
///// THTTPRequest.Create - thread constructor ////////////////////////////
///////////////////////////////////////////////////////////////////////////////
// RequestURL - the requested URL
constructor THTTPRequest.Create(const RequestURL: string);
begin
// create and start the thread after create
inherited Create(False);
// free the thread after THTTPRequest.Execute returns
FreeOnTerminate := True;
// store the passed parameter into the field for future use
FRequestURL := RequestURL;
end;
///////////////////////////////////////////////////////////////////////////////
///// THTTPRequest.Destroy - thread destructor ////////////////////////////
///////////////////////////////////////////////////////////////////////////////
destructor THTTPRequest.Destroy;
begin
inherited;
end;
///////////////////////////////////////////////////////////////////////////////
///// THTTPRequest.Execute - thread body //////////////////////////////////
///////////////////////////////////////////////////////////////////////////////
procedure THTTPRequest.Execute;
var
Request: OleVariant;
begin
// COM library initialization for the current thread
CoInitialize(nil);
try
// create the WinHttpRequest object instance
Request := CreateOleObject('WinHttp.WinHttpRequest.5.1');
// open HTTP connection with GET method in synchronous mode
Request.Open('GET', FRequestURL, False);
// set the User-Agent header value
Request.SetRequestHeader('User-Agent', 'Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.0');
// sends the HTTP request to the server, the Send method does not return
// until WinHTTP completely receives the response (synchronous mode)
Request.Send;
// store the response into the field for synchronization
FResponseText := Request.ResponseText;
// execute the SynchronizeResult method within the main thread context
Synchronize(SynchronizeResult);
finally
// release the WinHttpRequest object instance
Request := Unassigned;
// uninitialize COM library with all resources
CoUninitialize;
end;
end;
///////////////////////////////////////////////////////////////////////////////
///// THTTPRequest.SynchronizeResult - synchronization method /////////////
///////////////////////////////////////////////////////////////////////////////
procedure THTTPRequest.SynchronizeResult;
begin
// because of calling this method through Synchronize it is safe to access
// the VCL controls from the main thread here, so let's fill the memo text
// with the HTTP response stored before
Form1.Memo1.Lines.Text := FResponseText;
end;
///////////////////////////////////////////////////////////////////////////////
///// TForm1.Button1Click - button click event ////////////////////////////
///////////////////////////////////////////////////////////////////////////////
// Sender - object which invoked the event
procedure TForm1.Button1Click(Sender: TObject);
begin
// because the thread will be destroyed immediately after the Execute method
// finishes (it's because FreeOnTerminate is set to True) and because we are
// not reading any values from the thread (it fills the memo box with the
// response for us in SynchronizeResult method) we don't need to store its
// object instance anywhere as well as we don't need to care about freeing it
THTTPRequest.Create('http://stackoverflow.com');
end;
end.
IWinHttpRequest est assez primitif. Attention avec le mode Async spécifié dans Open ()!
Si vous pensez que vous pouvez télécharger un gros fichier en utilisant un IStream qui est retourné par get_ResponseStream() et les écrire dans un fichier en petits morceaux, comme il arrive, vous avez tort.
peu importe si vous utilisez le mode Sync ou Async: IWinHttpRequest charge toujours la réponse entière du serveur en mémoire et get_responsestream () renvoie E_PENDING jusqu'à ce que le Tout le téléchargement a été stocké en mémoire.
Cette interface a été conçue uniquement pour les petits fichiers.
je vous suggère d'en savoir plus sur L'objet TThread. Créez une nouvelle classe qui hérite de TThread, outrepassez la méthode Execute, appelez CoInitialize (pour activer COM) et exécutez le code WinHTTPRequest. Lorsque la requête est terminée, utilisez Synchronize pour renvoyer le résultat au thread de premier plan. En outre, vous devriez être capable de saisir des exceptions dans une clause try/except dans la méthode Execute.
une autre option est de passer à L'objet IXMLHTTPRequest, qui a un propriété booléenne async. Attraper des événements avec la liaison tardive peut être assez difficile, mais vous pourriez vérifier la propriété de l'état à intervalles réguliers.