[Lazarus] WinINet STDCALL callback crash
Benito van der Zander
benito at benibela.de
Thu Mar 14 00:09:33 CET 2013
> 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.
An actually crash or just a segfault message in the debugger?
I have been using wininet in a similar way for years, and it throws an
error quite often, when run from within Lazarus.
But when called normally, without Lazarus everything works fine.
I think wininet and debuggers just do not play well together...
Benito
On 03/13/2013 05:51 PM, matthew at accordancebible.com wrote:
> 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
>
>
>
>
> --
> _______________________________________________
> Lazarus mailing list
> Lazarus at lists.lazarus.freepascal.org
> http://lists.lazarus.freepascal.org/mailman/listinfo/lazarus
More information about the Lazarus
mailing list