Do I need to call TCanvas.Refresh after RestoreDC? - delphi

I am maintaining some code that contains the following:
Canvas.Refresh;
SavedDC := SaveDC(Canvas.Handle);
try
// Paint Stuff to the Canvas
finally
RestoreDC(Canvas.Handle, SavedDC);
Canvas.Refresh;
end;
I have learned that TCanvas.Refresh is nothing like a component refresh. It does not cause anything to paint, it just invalidates the Font, Pen, and Brush of the canvas.
I don't understand why you would call .Refresh before Saving the DC and then after restoring it back. That seems to kind of defeat the purpose of the SaveDC/RestoreDC calls.
A more reasonable order for these calls seems to be:
SaveDC(Canvas.Handle)
Canvas.Refresh
try
// Do my painting
finally
RestoreDC(Canvas.Handle, SavedDC);
end;
Since I have never seen or used the TCanvas.Refresh method I wanted to check and make sure I understood this correctly.

Here is an explanation - http://edn.embarcadero.com/article/27786
Calling Refresh after RestoreDC guarantees synchronization between TCanvas state and underlying device context.
Not sure that calling Refresh before SaveDC is necessary in modern Windows versions, but where is nothing wrong in it.
I would recommend to leave the code as is.

Related

Capturing all windows messages to an application

Is there a global WinProc for all windows in an application or a way to capture all paint messages to the application for a brief period of time? Some of the third party libraries that we use add their own wndproc's to controls (e.g. DevExpress ribbon, Docking Manager).
We have some code that should be run in a background thread but that's not possible at the moment. This code can take a long time to run and obviously the application becomes unresponsive during this time. We can't use things like processmessages because that would result in the code being reentered. To get around this I thought it should be possible to create our own version of ProcessMessages that looks for specific messages. The idea is that I would create a small panel with a progress bar and a cancel button and then only allow messages for the cancel button's windows handle.
The simplified code to process a single message looks something like this:
begin
if PeekMessage(aMsg, 0, 0, 0, PM_NOREMOVE) then
begin
Unicode := (aMsg.hwnd = 0) or IsWindowUnicode(aMsg.hwnd);
if Unicode then
MsgExists := PeekMessageW(aMsg, 0, 0, 0, PM_REMOVE)
else
MsgExists := PeekMessageA(aMsg, 0, 0, 0, PM_REMOVE);
if MsgExists then
begin
Result := True;
if aMsg.hwnd = aButtonWindowsHandle then
begin
TranslateMessage(aMsg);
if Unicode then
DispatchMessageW(aMsg)
else
DispatchMessageA(aMsg);
end
else
begin
// WM_PAINT is a special message. If you don't handle a WM_PAINT
// then windows will just stick it back in the queue again.
if (aMsg.message = WM_PAINT) and (aMsg.hwnd <> 0) then
begin
// Queue this paint message so we do an update when the
// processing is finished.
FQueuedPaintMessages.Add(aMsg);
// Paint nothing here otherwise Windows will send it again and
// insist that we paint it.
if BeginPaint(aMsg.hwnd, paintStruct) <> 0 then
EndPaint(aMsg.hwnd, paintStruct);
end;
end;
end;
end;
end;
This is called as follows:
while ProcessMessage(msg) do {loop};
This appeared to work correctly but during testing I picked up a couple of cases where one of the Windows API calls (PeekMeesage, TranslateMessage, DispatchMessage, or the two painting calls) is triggering a call back to our docking control's WndProc via KiUserCallbackDispatcher in ntdll.dll. The docking control is ultimately triggering a paint which is a problem. I am not sure what Windows API call it is because the stack trace is missing some lines at that point. It only happens on one of our test machines so I can't put in a breakpoint.
I am aware that this is far from an ideal solution and that we would be better off rewriting the code so that it can be run in a background thread but that would be a huge amount of work and is not feasible at this time.
It looks like SetWindowsHookEx with WH_MOUSE_LL might be a solution but that still needs a message loop.
Not so much an answer to your question than maybe a potential solution to your problem...
Instead of having a panel with a "cancel" button, instead display a label saying "Press and hold ESC to cancel process". Then, within your process you can get the status of the ESC key by calling GetAsyncKeyState at regular interval. I did not test it, but I'd expect it to work at least "well enough" for your needs.
The selected answer gave me a solution to my problem but #IInspectable answered the question about catching all of the paint messages. So for other people looking at that question. The answer is this:
"None of this can be made to work reliably with reasonable effort. It's just a clumsy attempt at fighting the system, and the system is going to win that one."
In other words. Don't try and do it.

Blocking Canvas

I have a form of my app that can have up to 1000 visual components, in which I draw each one once using Canvas of a bitmap, and save this bitmap of each component (a kind of double buffered), because each operation takes 20 ms.
I'm using threads to paint the bitmaps and send notifications with this bitmap to the MainThread, to refresh the visual components, the UI.
Theoretically, it would have to have a fluid form opening with the components being displayed as their bitmaps were painted in the threads, but in practice it was not fluid. I decided to take a look at the delphi's TCanvas and I noticed something staggering:
class var // <<<<<<<<<<<<<<<<<<<<<<<<<<<< class var
FLock: TObject;
function TCanvas.BeginScene(AClipRects: PClipRects = nil; AContextHandle: THandle = 0): Boolean;
begin
Lock;
...
end;
procedure TCanvas.EndScene;
begin
...
Unlock;
end;
class procedure TCanvas.Lock;
begin
TMonitor.Enter(FLock);
end;
class procedure TCanvas.Unlock;
begin
TMonitor.Exit(FLock);
end;
This definitely does not seem right. Why does the embarcadero make it impossible to work with TCanvas simultaneously in different threads? It's no use creating 10 threads to be doing bitmap drawings since everything will be processed 1 at a time...
Why does this exist?
Is there any workaround? What can happen if I make my version of
FMX.Graphics with only local monitors for each TCanvas?
Is there any third party lib with it own TCanvas?
I know that many will advise me to use native classes, JCanvas in android and CGContextRef in iOS, but I wanted a solution with TCanvas, because its job is to be a wrapper for drawing functions of all platforms, and to be easy to use.
============= #EDIT =============
I changed the Lock and Unlock of the TCanvas in the FMX.Graphics unit to use local instead of global monitors, as well as the BeginScene and EndScene of TContext3D in the FMX.Types3D unit.
I'm very apprehensive about this change but apparently the app is working normal, the biggest job was recompile the entire FMX.
Tbitmap is not really multithread. It's was made as multithread in Delphi Tokyo but with a very poor design (their is still many bug when you use Tbitmap in background thread, for example Tbitmap still use messaging notification that are not multithread at all and thus can result in random exception). What was done not bad in tokyo is to make the OpenGL context multithread (under android/ios), and that work quite well (but not the TTexture that are still bounds to Messaging, but you can easily update the source code of ttexture to correct it (You can look the source code of Alcinoe to know how to do it).
The only workaround for what you want to achieve is :
Don't use TBitmap but use instead Texture (because openGL Fully multithread without any lock)
Build the texture in background thread with native OS function (JCanvas in android and CGContextRef in iOS)
Avoid to use so many controls, but instead paint yourself all the texture that are ready and visible from the main thread (so in an onpaint event) at the right place
Yes I know it's a pain!

Why an application starts with FPU Control Word different than Default8087CW?

Could you please help me to understand what is going on with FPU Control Word in my Delphi application, on Win32 platform.
When we create a new VCL application, the control word is set up to 1372h. This is the first thing I don't understand, why it is 1372h instead of 1332h which is the Default8087CW defined in System unit.
The difference between these two:
1001101110010 //1372h
1001100110010 //1332h
is the 6th bit which according to documentation is reserved or not used.
The second question regards CreateOleObject.
function CreateOleObject(const ClassName: string): IDispatch;
var
ClassID: TCLSID;
begin
try
ClassID := ProgIDToClassID(ClassName);
{$IFDEF CPUX86}
try
Set8087CW( Default8087CW or $08);
{$ENDIF CPUX86}
OleCheck(CoCreateInstance(ClassID, nil, CLSCTX_INPROC_SERVER or
CLSCTX_LOCAL_SERVER, IDispatch, Result));
{$IFDEF CPUX86}
finally
Reset8087CW;
end;
{$ENDIF CPUX86}
except
on E: EOleSysError do
raise EOleSysError.Create(Format('%s, ProgID: "%s"',[E.Message, ClassName]),E.ErrorCode,0) { Do not localize }
end;
end;
The above function is changing control word to 137Ah, so it is turning on the 3rd bit (Overflow Mask). I don't understand why it is calling Reset8087CW after, instead of restoring the state of the word which was before entering into the function?
The 6th bit is reserved and ignored. Those two control words are in fact equal in the sense that the FPU behaves the same. The system just happens to set the reserved bit. Even if you attempt to set the value to $1332, the system will set it to $1372. No matter what value you ask the 6th bit to have, it will always be set. So, when comparing these values you have to ignore that bit. Nothing to worry about here.
As for CreateOleObject the authors decided that if you are going to use that function then you are also going to mask overflow when using the COM object, and indeed beyond. Who knows why they did so, and for 32 bit code only? Probably they found a bunch of COM objects that routinely overflowed, and so added this sticking plaster. It wasn't enough to mask overflow on creation, it also need to be done when using the object so The RTL designers chose to unmask overflow henceforth.
Or perhaps it was a bug. They decided not to fix it for 32 bit code because people relied on the behaviour, but they did fix for 64 bit code.
In any case this function does nothing very special. You don't need to use it. You can write your own that does what you want it to do.
Floating point control is a problem when working with interop. Delphi code expects unmasked exceptions. Code built with other tools typically masks them. Ideally you would mask exceptions when you call out of your Delphi code and unmask them on return. Expect other libraries to arbitrarily change the control word. Also be aware that Set8087CW is not thread safe which is a massive problem that Embarcadero have refused to address for many years.
There's no easy way forward. If you aren't using floating point in your program then you could simply mask exceptions and probably be fine. Otherwise you need to make sure that the control word is set appropriately at all points in all threads. In general that is close to impossible using the standard Delphi RTL. I personally handle this by replacing the key parts of the RTL with threadsafe versions. I have documented how to do so in this QC report: QC#107411.
Disclaimer: I debugged the questions in Delphi XE.
First, the second question.
If you look at the code of Set8087CW you will see that it stores the new FPU CW value in Default8087CW variable, and Reset8087CW restores FPU CW from Default8087CW; so the Reset8087CW call after Set8087CW does nothing at all, which is demonstrated by
Memo1.Lines.Clear;
Memo1.Lines.Add(IntToHex(Get8087CW, 4)); // 1372
Set8087CW( Default8087CW or $08);
Memo1.Lines.Add(IntToHex(Get8087CW, 4)); // 137A
Reset8087CW;
Memo1.Lines.Add(IntToHex(Get8087CW, 4)); // 137A
Evidently a bug.
Now the first question - it was interesting debugging exercise.
The Default8087CW value of Delphi VCL application is changed from hex 1332 to 1372 by Windows.CreateWindowEx function, called from Classes.AllocateHWnd, called from TApplication.Create, called from initialization section of Controls.pas unit.
Have a look at CreateWindowEx code - it explains what happens. I don't really want to discuss it further - the FPU support in Delphi is too messy and buggy.

Get window to refresh (etc) without calling Application.ProcessMessages?

I've got a legacy app here that has a few 'time-consuming' loops that get fired off as a result of various user interaction. The time-consuming code periodically updates something on the screen with progress information (typically a label) and then, seemingly to persuade the visual refresh to happen there-and-then, the code calls Application.ProcessMessages (argh!).
We all know now what kind of trouble this can introduce to a GUI app (being charitable, it was a more innocent time back then) and we're finding that sure as eggs, from time to time we get users achieving the impossible with the program because they're clicking on controls while the program is 'busy'.
What's the best way of periodically refreshing the visuals of the form without taking-on other events/messages etc?
My thoughts were to either;
- disable all of the controls before doing anything time-consuming, and leaving the '...ProcessMessages' calls in place to 'force' the refresh, or
- find another way to refresh a control periodically
I can do the former but it left me wondering - is there a better solution?
example code from legacy;
i:=0;
while FJobToBeDone do
begin
DoStepOfLoop;
inc(i);
if i mod 100 = 0 then
begin
UpdateLabelsEtc;
Application.ProcessMessages;
end;
end;
I can already hear you all fainting, at the back. :-)
If you call Update() on the controls after you have changed properties you will force them to redraw. Another way is to call Repaint() instead of Refresh(), which implies a call to Update().
You may need to call Update() on parent controls or frames as well, but this could allow you to eliminate the ProcessMessages() call completely.
The solution I use for long updates is by doing the calculations in a separate thread. That way, the main thread stays very responsive. Once the thread is done, it sends a Windows message to the main thread, indicating the main thread can process the results.
This has some other, severe drawbacks though. First of all, while the other thread is active, you'll have to disable a few controls because they might restart the thread again.
A second drawback is that your code needs to become thread-safe. This can be a real challenge sometimes. If you're working with legacy code, it's very likely that your code won't be thread-safe.
Finally, multi-threaded code is harder to debug and should be done by experienced developers.
But the big advantage of multi-threading is that your application stays responsive and the user can just continue to do some other things until the thread is done. Basically, you're translating a synchronous method into an asynchronous function. And the thread can fire several messages indicating certain controls to refresh their own data, which would be updated immediately, on the fly. (And at the moment when you want them to be updated.)
I've used this technique myself quite a few times, because I think it's much better. (But also more complex.)
Do not call Application.Processmessages, This is slow and might generate unlimited recursion.
For example, to update everything in Panel1 without flick, we can use this method:
procedure TForm1.ForceRepaint;
var
Cache: TBitmap;
DC: HDC;
begin
Cache := TBitmap.Create;
Cache.SetSize(Panel1.Width, Panel1.Height);
Cache.Canvas.Lock;
DC := GetDC(Panel1.Handle);
try
Panel1.PaintTo(Cache.Canvas.Handle, 0, 0);
BitBlt(DC, 0, 0, Panel1.Width, Panel1.Height, Cache.Canvas.Handle, 0, 0, SRCCOPY);
finally
ReleaseDC(Panel1.Handle, DC);
Cache.Canvas.Unlock;
Cache.Free;
end;
end;
For better performance, the cache bitmap should be created at first and free when the process has finished
The technique you're looking for is called threading. It is a diffucult technique in programming. The code should be handled with care, because it is harder to debug. Whether you go with threading or not, you should definitely disable the controls that users should not mess with (I mean the controls that can effect the ongoing process). You should consider using actions to enable/disable buttons etc...
Rather than disable the controls, we have a boolean var in the form FBusy, then simply check this when the user presses a button, we introduced it for the exact reasons you mention, users clicking buttons while they wait for long running code to run (it scary how familiar your code sample is).
So you end up with something like
procedure OnClick(Sender:TObejct);
begin
if (FBusy) then
begin
ShowMessage('Wait for it!!');
Exit;
end
else FBusy := True;
try
//long running code
finally
FBusy := False;
end;
end;
Its impotent to remember to rap the long running code up in a try-finally block in case of exits or exception, as you would end up with a form that will not work.
As suggested we do use threads if its for code that will not affect the data, say running a report or data analysis, but some things this is not an options, say if we are updating 20,000 product records, then we don't want anyone trying to sell or other wise altering the records mid flight, so we have to block the application until it is done.

In delphi 7, is `try ... except raise; end;` meaningful at all?

In some Delphi 7 code I am maintaining, I've noticed a lot of instances of the following:
with ADOQuery1 do begin
// .. fill out sql.text, etc
try
execSQL;
except
raise;
end;
end;
It seems to me that these try blocks could be removed, since they do nothing. However, I am wary of possible subtle side-effects..
Can anyone think of any instances in which these blocks could actually do anything that wouldn't happen without them there?
In this context, the raise operation has no effect and should be removed becuase its simply re-raising the exception that the exception block just caught. raise is typically used to transfer control to the end of the block when no appropriate error handling is available. In the following we handle the custom exception, but any other exception should be handled elsewhere.
try
someOperation;
except
on e: ECustomException do
SomeCustomHandelr;
else
begin
// the raise is only useful to rethrow the exception to an encompasing
// handler. In this case after I have called my logger code. as Rob
// mentioned this can be omitted if you arent handling anything because
// the compiler will simply jump you to the next block if there is no
// else.
LogUnexpectedException('some operation failed',e);
raise;
end;
end;
Be careful that there is similar looking form without the "raise" that DOES have the side effect of eating/hiding any exceptions. practicies by very unscrupulous developers who have hopefully moved on to positions with the competition.
with ADOQuery1 do begin
// .. fill out sql.text, etc
try
execSQL;
except
// no handler so this just eats any "errors"
end;
Removing the except code in above code snippet will make no difference. You can (and I believe you should since it is reducing the readability) remove it.
Okay, really two questions here.
First, it is meaningful: if execSQL throws an exception, it's caught by the try block and forwarded to the except. Then it's forwarded on by the raise to the next higher block.
Second, is it useful? Probably not. It almost certainly is the result of one of three things:
Someone with pointy hair wrote a coding standard that said "all operations that can throw an exception must be in a try block."
Someone meant to come back and turn the exceptions made by the execSQL statment into some other, more meaningful, exception.
Someone new wasn't aware that what they'd written was isomorphic to letting the uter environment worry about the exception, and so thought they must forward it.
I may have answered a bit fast, see at the end...
Like it is, it is useless for the application.
Period!
Now on the "why" side. It may be to standardize the exceptions handling if there /was/will be/is in other places/ some kind of logging code inserted before the raise:
try
execSQL;
except
// Log Exception..
on E: Exception do
begin
LogTrace(Format('%s: Exception Message[%s]',[methodname, E.Message]));
raise;
end;
end;
or for Cleanup code:
try
execSQL;
except
//some FreeAndNil..
raise;
end;
Update: There would be 1 case where I would see some use just like it is...
... to be able to put a Breakpoint on the raise line, to get a chance to see what's going on in the context on that block of code.
This code does nothing, other than to allow the original programmer to place a breakpoint on the 'Raise' and to see the exception closer in the source to its possible cause. In that sense it a perfectly reasonable debugging technique.
Actually, I should posted this as comment to François's answers, but I don't know is it possible to insert formatted code there :( So I'm posting this as answer.
2mghie:
The second one is completely unidiomatic, one would use finally instead.
No, "finally" will cleanup object always. "Except" - only on exception. Consider the case of function, which creates, fills and return an object:
function CreateObj: TSomeObj;
begin
Result := TSomeObj.Create;
try
... // do something with Result: load data, fill props, etc.
except
FreeAndNil(Result); // oops: bad things happened. Free object to avoid leak.
raise;
end;
end;
If you put "finally" there - function will return nil always. If you omit "try" block at all - there will be resources leak in case of exception in "...".
P.S. Of course, you can use "finally" and check ExceptObj, but... isn't that ugly?
The title contains quite a broad question, while its explanation gives a more specific example. So, my answering to the question as how it proceeds from the example, can doubtly add anything useful to what has already been said here.
But, maybe Blorgbeard indeed wants to know whether it is at all meaningful to try ... except raise; end. In Delphi 7, if I recollect correctly, Exit would trigger the finally part of a try-finally block (as if it were some sort of exception). Someone might consider such behaviour inappropriate for their task, and using the construction in question is quite a workaround.
Only it would still be strange to use a single raise; there, but then we should have talked about usefulness rather than meaningfulness, as Charlie has neatly observed.
This code does nothing except re-raising an exception that will allready be raised without this try except block. You can safely remove it.

Resources