unit Unit1;
interface
uses
Windows, RichEdit, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms,
Dialogs, StdCtrls, ComCtrls, Buttons;
type
TForm1 =
class(TForm)
RichEdit1: TRichEdit;
SpeedButton1: TSpeedButton;
SpeedButton2: TSpeedButton;
Label1: TLabel;
procedure SpeedButton1Click(Sender: TObject);
procedure RichEdit1KeyDown(Sender: TObject;
var Key: Word;
Shift: TShiftState);
procedure SpeedButton2Click(Sender: TObject);
private
procedure ApplicationIdleEvent(Sender: TObject;
var Done: Boolean);
{ Private-Deklarationen }
public
{ Public-Deklarationen }
end;
var
Form1: TForm1;
ThreadHandle,ThreadID : Cardinal;
ThreadActive : integer;
ThreadBeenden : integer;
AEditStreamStruc : TEditStream;
AMemoryStream : TMemoryStream;
FixFlag : Boolean;
BreakFlag : integer;
// zum Breaken der Callback-Funktion von außen
ChrCounter : integer;
implementation
{$R *.dfm}
function EditStreamOutCallbackFunc(dwCookie: Longint; pbBuff: PByte;
cb: Longint;
var pcb: Longint): DWORD;
stdcall;
begin
if BreakFlag = 1
then begin
// wenn also 'draußen' das Break-Flag auf 1 (~true) gesetzt wurde:
Result := $ffffffff;
// heißt: Abbruch
exit;
end;
Result := 0;
// heißt: auch danach ggf. weiter auslesen
try
pcb := AMemoryStream.
Write(pbBuff^,cb);
except
Result := 1;
// heißt: Abbruch
end;
if (pcb <> cb)
then Result := 1;
// heißt: Abbruch
end;
// . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
procedure AThread;
begin
repeat
AMemoryStream.Position := 0;
with AEditStreamStruc
do begin
dwCookie := 0;
dwError := 0;
pfnCallback := @EditStreamOutCallbackFunc;
end;
form1.RichEdit1.Perform(EM_STREAMOUT, SF_RTF, Longint(@AEditStreamStruc));
InterlockedExchange(ThreadActive,0);
SuspendThread(ThreadHandle);
until ThreadBeenden = 1;
end;
//------------------------------------------------------------------------------
procedure TForm1.ApplicationIdleEvent(Sender: TObject;
var Done: Boolean);
begin
if FixFlag
then begin
FixFlag := false;
InterlockedExchange(BreakFlag,0);
// Diese und die nächste Zeile existieren nur zur Erzeugung eines künstlichen Breaks,
if SpeedButton2.Caption = '
Break'
then //...zwecks einfachen debuggens desselbigen
begin InterlockedExchange(BreakFlag,1); SpeedButton2.Caption := '
no Break'
end;
InterlockedExchange(ThreadActive,1);
ResumeThread(ThreadHandle);
end;
end;
procedure TForm1.RichEdit1KeyDown(Sender: TObject;
var Key: Word;
Shift: TShiftState);
begin
InterlockedExchange(BreakFlag,1);
while ThreadActive = 1
do sleep(1);
FixFlag := true;
// die nächsten 2 Zeilen dienen nur der Anzeige wann der Absturz auftritt
inc(ChrCounter);
label1.Caption := IntToStr(ChrCounter);
end;
//-------------------------------------------------------------------------------
procedure TForm1.SpeedButton1Click(Sender: TObject);
const AWord = 13 + 10*256;
InputLen = 6000000;
type ChB = ^Byte; ChW = ^Word;
var AStream : TMemoryStream;
I : integer;
begin
SendMessage(RichEdit1.Handle,EM_SETLIMITTEXT,$7FFFFFFE,0);
AStream := TMemoryStream.Create;
AStream.SetSize(InputLen);
for I := 0
to InputLen-1
do ChB(integer(AStream.Memory)+I)^:=65;
for I := 1
to InputLen
div 100
do ChW(integer(AStream.Memory)+I*100-2)^:=AWord;
RichEdit1.Lines.LoadFromStream(AStream);
AStream.Free;
ThreadBeenden := 0;
ThreadActive := 0;
ThreadHandle := BeginThread(
Nil,0,@AThread,
NIL,CREATE_SUSPENDED,ThreadID);
SetThreadPriority(ThreadHandle,THREAD_PRIORITY_NORMAL);
Application.OnIdle := ApplicationIdleEvent;
end;
//-------------------------------------------------------------------------------
// Diese Proc erzeugt nur einen künstlichen Break, bzw. eine entsprechende
// Debug-Möglichkeit eines Breaks dieser obigen Callback-Funktion
procedure TForm1.SpeedButton2Click(Sender: TObject);
begin
SpeedButton2.Caption := '
Break';
end;
initialization
AMemoryStream := TMemoryStream.Create;
AMemoryStream.SetSize(7000000);
// sollte vorab schon entsprechend groß sein
FixFlag := false;
finalization
AMemoryStream.Free;
InterlockedExchange(ThreadBeenden,1);
ResumeThread(ThreadHandle);
CloseHandle(ThreadHandle);
end.