Keyboard Management in Pascal - keyboard

I'm a beginner in Pascal and I'm working on a small WIngraph game. At some point on the game, the character (which is a block) has to lay down (the block gets half of its original height). I want this to happen while holding the arrow-down key but the way I implemented it is not actually working. Another problem I have is I don't know how to read keys simultaneously (that would be needed when, for example, running to the right and jumping).
That's how I tried to write it:
procedure joystick;
begin
key:=readkey;
case key of
#0:begin
key:=readkey;
case key of
#80:with block do
begin
y1:=y2-100; //make it get half of its height
repeat
moveblock; //these are the drawing routines.
moveball; //they are in another procedure, which is the 'main loop'
collisioncheck;
draw; //i expected the code to run inside here with the block's
alternateball; //height changed, and as soon as the arrow key gets released
updateGraph(updateNow); //it should go back to the 'main loop'
killball;
delay(10);
until keypressed = false; //<--thats what i think is not working
y1:=y2-200; //this would make the block get normal again
end;
end;
end;
end;
I expected the code to run fine while the key was pressed and as soon as its released, the block should get its normal height and then the program would run based on its main loop, but outside of this procedure.
Everything is working, except that key-holding thing.

It does not work because after each keypressed() you should have a readkey(). The function keypressed() returns true until you call readkey() again.
Demo:
uses crt;
var c:char;
i:longint;
begin
while c<>#27 do
begin
while not keypressed() do
begin
clrscr;
writeln('not pressing anything');
delay(500);
end;
i:=0;
while keypressed() do
begin
clrscr;
c:=readkey();
if(c=#0) then
c:=readkey();
inc(i);
writeln(c,' ',i);
delay(300);
end;
end
end.

If you use freepascal/Lazarus:
don't use unit crt together with wingraph, but use wincrt. Wingraph hooks into win32 GUI events, while (win32) crt hooks into works via console API calls. Wincrt hooks into GUI (message pump) events.
preferably don't use *crt at all, but better use unit keyboard
Have a look in the Free Pascal examples, it contains several little games (a tetris and a samegame implementation) that optionally can also work with wingraph and unit keyboard. There is even some unit for highscores and a simple lineediting procedure on top of keyboard and wingraph.
Next time, please provide more precise details about the development platform (and version) that you use.

Related

( Delphi fmx ) Can you create UI controls in a background thread without blocking user interface

I'm wondering if it's possible to create UI elements , even a complete form, in a background thread ( "without using it of course" ) , and once it's done, make it available in main thread to be shown.
It's relatively easy now to separate time consuming data operations in background threads and synchronize the results with your main thread but what if creating the UI itself IS the time consuming operation ?
If possible, you could maybe have a fast startup screen and then start a background thread to create a set of forms. Whenever one is ready, it enables a menu item in the main thread so that it can be used.
I tried simple code, but it freezes immediatly. Is it possible ?
Execute in main program :
...
// declare var in main form
public
{ Public declarations }
lForm : TForm ;
...
// Execute e.g. with button click in main form
TThread.CreateAnonymousThread( procedure begin
// this stops application from running when the form is show
// in the synchronize part
lForm := TForm1.Create(Self);
TThread.Synchronize(nil,
procedure begin
// This does not stops the application but freezes the gui of course
//lForm := TForm1.Create(Self);
lForm.Parent := Self ;
lForm.Show ;
end );
end ).Start ;`
procedure TForm1.FormCreate(Sender: TObject);
begin
sleep(2000);
end;
...
If it's not possible, how could you do this in the main thread while still 'simulating' that your main thread is responsive ? ( by calling something like application.processmessages regularly or so ? )
I'm using Delphi Rio 10.3, fmx framework.
I'm wondering if it's possible to create UI elements , even a complete
form, in a background thread ( "without using it of course" ) , and
once it's done, make it available in main thread to be shown.
NO.
Creating and accessing UI controls from background thread is not thread safe.
While you can create some proof of concept code that seemingly works, such code is inherently broken. It may fail randomly.
So , in summary, UI controls can only be used safely in the thread they are created in, and you can't change this behaviour after their creation time ( and make them 'belonging' to another thread as if they were created there in the first place ).
It might be though that conceptually, creating forms, that do not interact with another can work looking at
How to make a form in a DLL embedded inside my application?
I'm assuming that also here, the form is indeed created in different thread , probably even in a different process, right ?
I found that the following does not freeze instantly, but if that's pure luck for now or wisdom, I'm unsure..
Instead if making the form visible in the synchronize part of the background thread, I do it 'really' in the main thread...
( I could understand that as long as you don't give any parent to UI controls, they are 'safe'. How would the main thread know about their existence ? )
I might test this a bit further afterall.
procedure TTabbedForm.Button1Click(Sender: TObject);
begin
TThread.CreateAnonymousThread( procedure begin
lForm := TForm1.Create(Self);
TThread.Synchronize(nil,
procedure begin
//lForm.Parent := Self ;
//lForm.Show ;
Button2.Enabled := True ;
end );
end ).Start ;
end;
procedure TTabbedForm.Button2Click(Sender: TObject);
begin
if Assigned(lForm) then begin
lForm.Parent := Self ;
lForm.Show ;
end;
end;

Correct logging within thread without dialog with Eurekalog

I have a Delphi 10 project using the latest version of EurekaLog. I'm currently using EurekaLog to help me debug problems in my production clients.
I noticed that EurekaLog wasn't registering errors that happened within threads. After I started reading up on it, I found that I need to change from TThread to TThreadEx, and add the following code at the start of my Execute overriden method.
SetEurekaLogStateInThread(ThreadID, true);
Despite this, when an error happens, it does not generate an event in the EL file.
If I add ExceptionManager.StandardEurekaError('TThrdSincArquivos.Execute => ' + ex.Message); on the try..except, it does log. But the stack trace is displayed as if the error occurred on the line where I call StandardEurekaLog(), not on the line where the error actually occurred. This defeats the purpose of the whole thing.
Another problem is that it displays a dialog box, which I don't want, since the error occurred inside a background thread. I just want it logged. I should get a dialog only with errors on the main thread.
How can I achieve theses results within the thread?
Actually log the error with the correct stack.
When on the main thread, display the dialog, but within a thread, just log with no dialog.
EDIT
Below is my EurekaLog Muti-threading configuration
Here is my thread declaration:
unit ThrdSincArquivos;
interface
uses
System.Classes, System.SysUtils, System.Generics.Collections, REST.Client, REST.Types,
System.JSON, Data.DB, Datasnap.DBClient, FireDAC.Comp.Client, FireDAC.Stan.Param, System.SyncObjs, EBase, EExceptionManager, EClasses;
type
TThrdSincArquivos = class(TThreadEx)
private
My thread's Create
constructor TThrdSincArquivos.Create(pPrimeiraExec: boolean; tipoSincParam: TTipoSinc);
begin
inherited Create(true);
NameThreadForDebugging('TThrdSincArquivos');
primeiraExec := pPrimeiraExec;
tipoSinc := tipoSincParam;
executadoThreadSinc := false;
FreeOnTerminate := true
end;
The start of my Execute
procedure TThrdSincArquivos.Execute;
var
contador: Integer;
begin
inherited;
try
and the end of the Execute
except
on ex: Exception do
begin
oLog.GravarLog(ex, 'TThrdSincArquivos.Execute => FIM');
end;
end;
end;
It refuses to log any exception to the Elf file. I tried to add a raise after my own log routine, but it still didn't help. It should log, but it isn't, unless I explicitly call the StandardEurekaError, but I get the stack wrong, and I get the dialog.
When you are using TThread class - it saves thread exception to .FatalException property, which you are supposed to handle in some way. Either from thread event, or from other (caller) thread. EurekaLog does not break this behaviour. E.g. your previosly written code will not change its behaviour when you enable EurekaLog. That way your properly written code would work correctly both with and without EurekaLog.
How your code is currently handling thread exceptions? Are you doing something like ShowMessage or custom logging? This obviosly would not work with EurekaLog, it does not know that you are processing exceptions with ShowMessage or your own custom logging code. You probably want something like Application.ShowException or re-raise in caller thread.
If you can not use default RTL/VCL processing (which is hooked by EurekaLog) for some reason - then you need to tell EurekaLog that you want to handle this particular exception. For example, from docs: you can use (for example) HandleException(E); from EBase unit:
Thread.WaitFor;
if Assigned(Thread.FatalException) then
begin
// Your old code is here
// Do your own thing: show message, log, etc.
// Tell EurekaLog to do its thing:
HandleException(Thread.FatalException);
end;
You would probably want to set exception filter or use events to disable dialogs for thread exceptions, because presumably you have already processed exception yourself (e.g. already showed message).
There is A LOT more ways to handle exception in threads, and EurekaLog's docs illustrate each thread case (like BeginThread, TThread, thread pools, etc.) with several possible options. It is just not reasonable to pack all this information into a single answer.
If, for some reason, you do not have code that processes .FatalException property of TThread - then you can use TThreadEx class and its .AutoHandleException property to handle exceptions automatically when thread exits, as described here:
type
TMyThread = class(TThreadEx)
protected
procedure Execute; override;
end;
procedure TMyThread.Execute;
begin
// ... your code ...
end;
procedure TForm1.Button1Click(Sender: TObject);
var
Thread: TMyThread;
begin
Thread := TMyThread.Create(True, 'My thread');
Thread.AutoHandleException := True; // <- added
Thread.FreeOnTerminate := True;
Thread.Start;
Thread := nil; // never access thread var with FreeOnTerminate after Start
end;
However, be aware that you code will not work properly (e.g. will ignore exceptions) if you decide to disable EurekaLog in the future. Because if you remove EurekaLog from your project - then your project will have no code to handle thread exceptions!
P.S.
I need to change from TThread to TThreadEx, and add the following
code at the start of my Execute overriden method.
SetEurekaLogStateInThread(ThreadID, true);
That is slightly incorrect: you can do either one or another, but not both. And there are other ways to tell EurekaLog that it should hook exceptions in this thread.
Basically, exception life has two stages: raise and handle. EurekaLog hooks both stages when they are implemented in default RTL/VCL code. You need to explicitly indicate which threads you want to hook, because you probably want to ignore system / 3rd party threads, which you have no control over. And it so happens that default processing for TThread does not exist in RTL/VCL. That is why there is nothing to hook.

List Index Out of Bounds on screen.forms

I do some reporting on a form with reportbuilder.
On the main form I select some items on a grid and then a generate the reports of the items.
I want to do this in a Tthread but i get an error 'List index out of bounds'.
Here is the call stack:
Classes.TList.Get(1244868)
Classes.TList.Get(???)
Forms.TScreen.GetCustomForms(???)
Forms.TApplication.DoActionIdle
Forms.TApplication.Idle(???)
Forms.TApplication.HandleMessage
Forms.TApplication.Run
Seems some form is either not being added to the Screen.Forms
collection in a timely manner or one is being freed from it during the
loop in DoActionIdle.
Any ideas on how to circumvent this problem?
I work on windows XP and delphi 2010.
I Also I've the problem with a test procedure on my application
TForm3 is just a form with no code.
TDebugThread = class(TThread)
protected
procedure Execute; override;
public
constructor Create();
end;
constructor TDebugThread.Create;
begin
FreeOnTerminate := True;
inherited Create(False);
end;
procedure TDebugThread.Execute;
var
oReport: DeBugReport.TForm3;
begin
inherited;
oReport:= DeBugReport.TForm3.Create(Nil);
try
sleep(1000);
finally
oReport.Free;
end;
end;
....
procedure RunThread();
begin
TDebugThread.Create();
end;
Recapitulation:
I have a list of some Intervention on a form. Each detail and resumation of the intervention can I print on 2/5 reports. Therefore I use reports components (reportbuilder) on another form (not visible). The new feature was to multiselect some interventions on the list and set the reports in a folder in pdf format. That's was simple just on each intervention call the reportform and some parameters to change and save into pdf.
But this take to long. The user must wait until the procedure was ended. No problem I set the procedure in a thread. But there I get the error 'List index out of bounds'. ArgggArggg, I was suspected that the reportform (created, to his job and then destroyed) the problem was but hoped that there was another solution. I was thinking to change the TForm into TDataModule. Can I set all the components of the form into the datamodule. I use the TDbGrid to see some values in design. But in the Tdatamodule I can't set a TDBGrid. Ok, I can live without the TDbGrid. So I transformed the TForm into TDataModule.
But the TDataModule is not the answer. There I get the error 'Graphics.OutOfResource' from a TBitmap. I think that the TBitmap is calling from the TppReport. Now I'm done. I'm changing my code all more than 2 days with no result. I leave the TThread for this time.
Let's take a look at TApplication.DoActionIdle:
procedure TApplication.DoActionIdle;
var
I: Integer;
begin
for I := 0 to Screen.CustomFormCount - 1 do
with Screen.CustomForms[I] do
if HandleAllocated and IsWindowVisible(Handle) and
IsWindowEnabled(Handle) then
UpdateActions;
end;
Let's assume that Screen.CustomFormCount and is implemented correctly and always returns the number of items indexed by Screen.CustomForms. In which case the conclusion is that the body of the loop is deleting a form. That is Screen.CustomFormCount is changing during the execution of the loop.
The only way that can happen is if one of the form's action update handlers results in a form being deleted. So, I can't tell you any more than that, but this analysis should lead you to the root cause of the problem.
And the second part of your question is quite simple. You cannot use VCL components outside the main GUI thread.
In fact it is plausible that destroying the VCL form in your thread is what is leading to Screen.CustomFormCount changing during the execution in the GUI thread of TApplication.DoActionIdle.

Is there any problem to using this code in a Thread ? (Delphi)

i use this code in a thread (through Indy Onexecute event) . is there any problem ?
function TFrmMain.ShellExecute_AndWait(FileName, Params: string): bool;
var
exInfo: TShellExecuteInfo;
Ph: DWORD;
begin
FillChar(exInfo, SizeOf(exInfo), 0);
with exInfo do
begin
cbSize := SizeOf(exInfo);
fMask := SEE_MASK_NOCLOSEPROCESS or SEE_MASK_FLAG_DDEWAIT;
Wnd := GetActiveWindow();
exInfo.lpVerb := 'open';
exInfo.lpParameters := PChar(Params);
lpFile := PChar(FileName);
nShow := SW_NORMAL;
end;
if ShellExecuteEx(#exInfo) then
Ph := exInfo.hProcess
else
begin
Result := true;
exit;
end;
while WaitForSingleObject(exInfo.hProcess, 50) <> WAIT_OBJECT_0 do
begin
end;
CloseHandle(Ph);
Result := true;
end;
MSDN has this advice:
Because ShellExecuteEx can delegate execution to Shell extensions (data sources, context menu handlers, verb implementations) that are activated using Component Object Model (COM), COM should be initialized before ShellExecuteEx is called. Some Shell extensions require the COM single-threaded apartment (STA) type. In that case, COM should be initialized as shown here:
CoInitializeEx(NULL, COINIT_APARTMENTTHREADED | COINIT_DISABLE_OLE1DDE)
There are instances where ShellExecuteEx does not use one of these types of Shell extension and those instances would not require COM to be initialized at all. Nonetheless, it is good practice to always initalize COM before using this function.
(In Delphi, you'd of course replace the first parameter with nil and use or for the bitwise operation.)
Raymond Chen recently wrote about the consequences of getting this wrong. The specific example was that the function might fail with the Error_Access_Denied error code.
That's the only potential multithreading issue I see in your code. Below are further things that occurred to me when I read your code, although they have nothing to do with multithreading (and not even much to do with Indy).
You have a peculiar way of waiting for the program to stop running. You repeatedly wait for 50 milliseconds at a time, but if the process isn't finished yet, you do nothing but wait again. Describe your intention more accurately by specifying Infinite for the timeout.
The function always returns True. If there's no useful return value, then you should just make it a procedure so there's no return value at all. Don't confuse the caller with useless information. If you're going to keep it as a function, then use the Delphi native type Boolean instead of the Windows compatibility type Bool for the return type.
I'm a little wary about the idea of a server executing user-interactive programs upon receipt of network messages.
Notice when MSDN says you might not get a process handle. There are cases when ShellExecuteEx can service your request without creating a new process, so you'll have nothing to wait on.
The user might end up using the program awhile, and your server will be stuck waiting all that time. I wonder whether it really needs to wait at all. Is the client going to be waiting for a response from the server, too?

Named threads in Delphi - what is that for?

When you create a TThread descendant using the tool palette in your BDS, you can provide a name for the thread. Here's the auto-generated code. You just call the SetName() function in the Execute method and the thread calling this method is given a name in a kind of weird way...
{$IFDEF MSWINDOWS}
type
TThreadNameInfo = record
FType: LongWord; // must be 0x1000
FName: PChar; // pointer to name (in user address space)
FThreadID: LongWord; // thread ID (-1 indicates caller thread)
FFlags: LongWord; // reserved for future use, must be zero
end;
{$ENDIF}
{ TTestThread }
procedure TTestThread.SetName;
{$IFDEF MSWINDOWS}
var
ThreadNameInfo: TThreadNameInfo;
{$ENDIF}
begin
{$IFDEF MSWINDOWS}
ThreadNameInfo.FType := $1000;
ThreadNameInfo.FName := 'ThreadName';
ThreadNameInfo.FThreadID := $FFFFFFFF;
ThreadNameInfo.FFlags := 0;
try
RaiseException( $406D1388, 0, sizeof(ThreadNameInfo) div sizeof(LongWord), #ThreadNameInfo );
except
end;
{$ENDIF}
end;
I find it really useful during debugging for you can see not only TIDs, but also thread names assigned that way. You know which thread is which thanks to that.
Please tell me, however, if the name assigned can be accessed in any way. Can it be read based on a thread's handle? Or can it be read even from 'outside' the process by another process? You know, there are applications which list your processes and the threads working in them. Will this name be accessible to apps like that?
Thanks!
Actually, thread names are just used for debugging purposes and nothing else, really. In your code, you could just identify threads by using the ThreadID. And if you want to keep a name with those thread ID's, keep a separate (dictionary) list which maps each thread ID to whatever name you like.
The hack that you see does a nasty trick. The exception that is raised is captured by the debugger, which just handles it as a special exception and will just continue execution. The exception flag just tells the system to continue after the exception is raised, since the code will handle it. The empty except-clause is handling the exception within your code. It's just a dirty trick to communicate with the debugger, which will zee the exception and remember the name you've just passed to it...
It's entirely a debugging feature. In fact, the thread object doesn't even keep track of its own name. It sends it directly to the debugger, but doesn't store a copy of the name for itself. It's not accessible from within your own program or from anywhere else, except the debugger.

Resources