[Lazarus] WinINet STDCALL callback crash

matthew at accordancebible.com matthew at accordancebible.com
Wed Mar 13 17:51:29 CET 2013


Sven, 

Thank you very much for your threading example below.  I have used the model several times to build threaded implementations.  However, I still get frequent, random segfaults when calling Windows functions.  My current attempt, as simple as I can make it, is below.  About 50% of the time, the first command in the execute procedure works fine; the other times it causes a crash.  Might you or any others have suggestions on why this is?  

Thank you,
Matthew

<pre>

TYPE
		DownloadThread = CLASS(TThread)
			PROCEDURE EXECUTE; OVERRIDE;

			PUBLIC
				theURL, theDest: AnsiString;

			PUBLIC
				CONSTRUCTOR Create(URLString: Str; dest: Str);
		END;

VAR //global
		gTheURLString: Str;
		dest: Str;

IMPLEMENTATION

	CONSTRUCTOR DownloadThread.Create(URLString: Str; dest: Str);
	BEGIN
		theURL := URLString;
		theDest := dest;

	  FreeOnTerminate := True;
	  inherited Create(False);
	END;

	PROCEDURE DownloadThread.execute;
	{ OVERRIDE }
	VAR
	  hInet: HINTERNET;
	  hURL: HINTERNET;
	  Buffer: array[0..1023] of Byte;
	  BufferLen, amt: cardinal;
	  f: file;
	  success: BOOLEAN;
	  appTitle: PChar;

	BEGIN
		appTitle := 'Lazarus App with Threading';
	  try
		  hInet := InternetOpen(appTitle, INTERNET_OPEN_TYPE_PRECONFIG, nil, nil, 0);
	    hURL := InternetOpenUrl(hInet, PChar(theURL), nil, 0, INTERNET_FLAG_RELOAD, 0);
	    try
	      FileMode := fmOpenWrite;
	      AssignFile(f, theDest);
	      try
	        Rewrite(f, 1);
	        amt := SizeOf(Buffer);
	        repeat
	          success := InternetReadFile(hURL, @Buffer, SizeOf(Buffer), BufferLen);
	          BlockWrite(f, Buffer[0], BufferLen, amt);
	          if Terminated then
	            Exit;
	        until BufferLen = 0;
	      finally
	        CloseFile(f);
	      end;
	    finally
	      InternetCloseHandle(hURL);
	    end;
	  FINALLY
	    InternetCloseHandle(hInet);
	  END;
	END;


....main program...

DownloadThread.Create(gTheURLString, dest);

</pre>


-----Original Message-----
From: "Sven Barth" <pascaldragon at googlemail.com>
Sent: Monday, February 25, 2013 11:51am
To: lazarus at lists.lazarus.freepascal.org
Subject: Re: [Lazarus] WinINet STDCALL callback crash

On 25.02.2013 17:42, matthew at accordancebible.com wrote:
> Ludo, Hans-Peter,
>
> Many thanks for your insights.
>
> Ludo, I am reviewing the msdn code example you posted; I have read quite a few but don't remember seeing that one.
>
> Hans-Peter, our project has so far been able to avoid the additional complexity posed by threads.  It would be with reluctance that we would turn to threading; however, if experimenting with Ludo's post content (see below) does not work, then would will use threads.  Might you know of an example implementation or code for asynchronous HTTP and/or FTP downloads?

In principle you could do it as follows:

=== example begin ===

type
   TDownloader = class(TThread)
   public type
     TCallback = procedure(aSender: TDownloader; aData: TStream) of object;
   private
     fCallback: TCallback;
     fUrl: String;
   protected
     procedure Execute; override;
   public
     constructor Create(const aUrl: String; aCallback: TCallback);
   end;

constructor TDownloader.Create(const aUrl: String; aCallback: TCallback);
begin
   // check that aCallback and aUrl are given and set up local variables
   // ...

   FreeOnTerminate := True;
   inherited Create(False);
end;

procedure TDownloader.Execute;
var
   ms: TMemoryStream;
begin
   ms := TMemoryStream.Create;
   try
     // here you use what ever synchronous API you want and store it's 
result in ms

     // when all data is received
     fCallback(Self, ms);
   finally
     ms.Free;
   end;
end;

// somewhere else

TDownloader.Create('http://example.org/whatever', @MyCallback);
// fire and forget

=== example end ===

Note: if you want to be able to cancel the download (which could be done 
by calling the thread's "Terminate" method which sets "Terminated" to 
"True") you should not set "FreeOnTerminate" to "True", check for 
"Terminated" in the thread's "Execute" method and capture the instance 
returned by "TDownloader.Create".

Regards,
Sven

--
_______________________________________________
Lazarus mailing list
Lazarus at lists.lazarus.freepascal.org
http://lists.lazarus.freepascal.org/mailman/listinfo/lazarus







More information about the Lazarus mailing list