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).

4
demandé sur kobik 2011-12-17 23:01:33

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.
3
répondu TLama 2011-12-18 10:38:45

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.

2
répondu Elmue 2013-08-10 01:46:15

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.

1
répondu Stijn Sanders 2011-12-17 21:37:49