Recent

Author Topic: [SOLVED] Access violation when ending program / Forms with Parent 'Application'  (Read 7544 times)

Hartmut

  • Hero Member
  • *****
  • Posts: 1000
Do you want to say that FormPV is created in a local procedure, shown modally and destroyed there? Like this:
...
I cannot imagine that this could pose any problem, it is standard in many of my applications.
Beside that my procedure is much 'bigger' and that my procedure is not local, but global inside of a unit, yes, the principle is the same.
Thanks a lot for clarification, that this local Form can not be the root cause for the AV.

Hartmut

  • Hero Member
  • *****
  • Posts: 1000
Another question occured: when a Form has an OnClose Event handler an in it  'CloseAction:=caFree' is set: at which time will this Form be destroyed?
 - always immediately after the OnClose Event exits?
 - or can/will this be (always) "later", e.g. when the next Application.ProcessMessages() is called (by my code or from the LCL) or when certain "messages" are handled by the LCL?
 - what is the latest possibility, when this Form is destroyed?
 - is there a difference, if the Form is the MainForm?
 - is there a difference, if the Parent of the Form is var 'Application'?
 - is there a difference, if the Form was shown modal or non modal?

Sorry for so detailed questions. I'm checking / reworking a lot of code which has many different conditions. And now I want to definitely learn and understand this subject to avoid more uncertainnesses and mistakes in the future :-)

Thaddy

  • Hero Member
  • *****
  • Posts: 18306
  • Here stood a man who saw the Elbe and jumped it.
Afaik it relies solely on Application.ProcessAsyncQueue and that works in FIFO order.
Due to censorship, I changed this to "Nelly the Elephant". Keeps the message clear.

Hartmut

  • Hero Member
  • *****
  • Posts: 1000
There's no guarantee that valgrind will pick up anything, but it very well might uncover e.g. a hidden memory corruption bug that sometimes causes a segfault further down the line.
Besides, basic usage of valgrind isn't nearly as complicated as the wiki makes it out to be:

  • Install  valgrind  with  sudo apt install valgrind
  • Check the  -gv  (Generate code for valgrind) option in the project settings and recompile
  • Run your program like so:  valgrind ./azul487
Because that sounded promising I tried valgrind for my very 1st time. But it took plenty of hours without getting a result. Maybe valgrind needs much more effort to learn it and to customize / configurate it in a reasonable way for each individual program and purpose...

Here comes a short extract of typically results of many runs:

Example 1:
valgrind --log-file=vg01.trc /hg/utis/azul
I only started my program and exited it immediately via the Close-Button.

Valgrind reported 10x "Conditional jump or move depends on uninitialised value(s)" and a summary of:
Code: Text  [Select][+][-]
  1. HEAP SUMMARY:
  2.     in use at exit: 2,168,819 bytes in 30,420 blocks
  3.   total heap usage: 503,830 allocs, 473,410 frees, 43,368,298 bytes allocated
  4.  
  5. LEAK SUMMARY:
  6.    definitely lost: 14,550 bytes in 47 blocks
  7.    indirectly lost: 156,052 bytes in 6,420 blocks
  8.      possibly lost: 20,470 bytes in 53 blocks
  9.    still reachable: 1,834,179 bytes in 22,731 blocks
  10.         suppressed: 0 bytes in 0 blocks
  11. Rerun with --leak-check=full to see details of leaked memory
  12.  
  13. Use --track-origins=yes to see where uninitialised values come from
  14. For lists of detected and suppressed errors, rerun with: -s
  15. ERROR SUMMARY: 158 errors from 10 contexts (suppressed: 0 from 0)

This sounds not good...
I checked the 1st complaint:
Code: Text  [Select][+][-]
  1. Conditional jump or move depends on uninitialised value(s)
  2.    at 0x41F8B4: SYSTEM_$$_INDEXBYTE$formal$INT64$BYTE$$INT64 (in /hg/utis/azul)
  3.    by 0x464BE2: LIB_$$_REPL_5C_ZVS$ANSISTRING$$ANSISTRING (lib.pas:2558)
  4.    by 0x46963C: LIB_$$_UTF8_ZVS$ANSISTRING$$ANSISTRING (lib.pas:3512)
  5.    by 0x4B359C: LCLLIB_$$_SETTOOLTIP$TCONTROL$ANSISTRING (LCLlib.pas:6550)
  6.    by 0x4B2DD9: LCLLIB_$$_SETLABELEX$TLABEL$SMALLINT$ANSISTRING$$SMALLINT (LCLlib.pas:6413)
  7.    by 0x51FFB6: AZUL1$_$TFORM1_$__$$_SET_ALL_POSITIONS$BOOLEAN$S40 (azul1.pas:20115)
  8.    by 0x52AC3E: AZUL1$_$TFORM1_$__$$_FORMCREATE$TOBJECT (azul1.pas:21943)
  9.    by 0x44C4B6: FORMS$_$TCUSTOMFORM_$__$$_DOCREATE (customform.inc:939)
  10.    by 0x44A12C: FORMS$_$TCUSTOMFORM_$__$$_AFTERCONSTRUCTION (customform.inc:149)
  11.    by 0x452CA3: FORMS$_$TFORM_$__$$_CREATE$TCOMPONENT$$TFORM (customform.inc:3184)
  12.    by 0x45CFC4: FORMS$_$TAPPLICATION_$__$$_CREATEFORM$TCOMPONENTCLASS$formal (application.inc:2239)
  13.    by 0x41F1BC: main (azul.pas:976)
The top most line in my sources is lib.pas:2558 which has:
Code: Pascal  [Select][+][-]
  1. type ansi = ansistring;
  2.  
  3. function repl_5C_ZVS(s: ansi): ansi;
  4.    {replaces '\' by 'LineEnding'}
  5.    begin
  6.    exit(strreplS_A(s,'\',LineEnding)); // this is line 2558
  7.    end;
  8.  
  9. function strreplS_A(s: ansi; alt,neu: ansi): ansi;
  10.    {replaces in 's' all occurrences of 'alt' by 'neu'}
  11.    var p: longint;
  12.    begin
  13.    p:=1;
  14.    repeat p:=strutils.PosEx(alt,s,p);
  15.           if p=0 then exit(s); {if not found}
  16.           delete(s,p,length(alt));
  17.           insert(neu,s,p);
  18.           inc(p,length(neu));
  19.    until  false;
  20.    end;
I can't find there a "Conditional jump or move depends on uninitialised value(s)"...

The other 9 complaints all lead also to a usage of above function strreplS_A().
I don't see how this can help me, because I get many complaints for the same source reason and can't find there something wrong.

Example 2:
valgrind --leak-check=full --log-file=vg02.trc /hg/utis/azul
I only started my program and exited it immediately via the Close-Button.

Additional to above 10 complaints valgrind now reported this 22 complaints:
Code: Text  [Select][+][-]
  1. 8 bytes in 1 blocks are definitely lost in loss record 407 of 9,037
  2. 8 bytes in 1 blocks are definitely lost in loss record 408 of 9,037
  3. 24 bytes in 1 blocks are definitely lost in loss record 2,593 of 9,037
  4. 34 bytes in 1 blocks are definitely lost in loss record 4,099 of 9,037
  5. 40 bytes in 1 blocks are definitely lost in loss record 4,461 of 9,037
  6. 48 (24 direct, 24 indirect) bytes in 1 blocks are definitely lost in loss record 5,077 of 9,037
  7. 84 bytes in 1 blocks are definitely lost in loss record 6,392 of 9,037
  8. 112 (80 direct, 32 indirect) bytes in 1 blocks are definitely lost in loss record 7,888 of 9,037
  9. 128 bytes in 1 blocks are definitely lost in loss record 8,027 of 9,037
  10. 232 (40 direct, 192 indirect) bytes in 1 blocks are definitely lost in loss record 8,333 of 9,037
  11. 320 (256 direct, 64 indirect) bytes in 1 blocks are definitely lost in loss record 8,458 of 9,037
  12. 432 (184 direct, 248 indirect) bytes in 1 blocks are definitely lost in loss record 8,568 of 9,037
  13. 520 bytes in 13 blocks are definitely lost in loss record 8,631 of 9,037
  14. 578 (184 direct, 394 indirect) bytes in 1 blocks are definitely lost in loss record 8,668 of 9,037
  15. 795 (136 direct, 659 indirect) bytes in 1 blocks are definitely lost in loss record 8,717 of 9,037
  16. 14,402 (1,024 direct, 13,378 indirect) bytes in 2 blocks are definitely lost in loss record 9,012 of 9,037
  17. 15,631 (512 direct, 15,119 indirect) bytes in 1 blocks are definitely lost in loss record 9,016 of 9,037
  18. 15,631 (512 direct, 15,119 indirect) bytes in 1 blocks are definitely lost in loss record 9,017 of 9,037
  19. 15,631 (512 direct, 15,119 indirect) bytes in 1 blocks are definitely lost in loss record 9,018 of 9,037
  20. 26,557 (7,680 direct, 18,877 indirect) bytes in 10 blocks are definitely lost in loss record 9,030 of 9,037
  21. 31,823 (1,024 direct, 30,799 indirect) bytes in 2 blocks are definitely lost in loss record 9,032 of 9,037
  22. 47,454 (1,536 direct, 45,918 indirect) bytes in 3 blocks are definitely lost in loss record 9,034 of 9,037

E.g. the last one (which has the largest amout of lost bytes) contains:
Code: Text  [Select][+][-]
  1. 47,454 (1,536 direct, 45,918 indirect) bytes in 3 blocks are definitely lost in loss record 9,034 of 9,037
  2.    at 0xD339B80: realloc (in /usr/libexec/valgrind/vgpreload_memcheck-amd64-linux.so)
  3.    by 0xE1B08AA: ??? (in /usr/lib/x86_64-linux-gnu/libfontconfig.so.1.12.1)
  4.    by 0xE1B4ED8: ??? (in /usr/lib/x86_64-linux-gnu/libfontconfig.so.1.12.1)
  5.    by 0xDCDF88B: ??? (in /usr/lib/x86_64-linux-gnu/libcairo.so.2.11800.0)
  6.    by 0xDFB48C7: ??? (in /usr/lib/x86_64-linux-gnu/libpangocairo-1.0.so.0.5200.1)
  7.    by 0xE42655D: ??? (in /usr/lib/x86_64-linux-gnu/libpangoft2-1.0.so.0.5200.1)
  8.    by 0xDBE0AD7: ??? (in /usr/lib/x86_64-linux-gnu/libpango-1.0.so.0.5200.1)
  9.    by 0xDBF4FAD: ??? (in /usr/lib/x86_64-linux-gnu/libpango-1.0.so.0.5200.1)
  10.    by 0xDBEA08D: ??? (in /usr/lib/x86_64-linux-gnu/libpango-1.0.so.0.5200.1)
  11.    by 0xDFB5A88: ??? (in /usr/lib/x86_64-linux-gnu/libpangocairo-1.0.so.0.5200.1)
  12.    by 0xDBF3A74: ??? (in /usr/lib/x86_64-linux-gnu/libpango-1.0.so.0.5200.1)
  13.    by 0xDBF45C7: ??? (in /usr/lib/x86_64-linux-gnu/libpango-1.0.so.0.5200.1)
but contains not even 1 line of my sources.

Another example, which contains not even 1 line of my sources:
Code: Text  [Select][+][-]
  1. 336 bytes in 1 blocks are possibly lost in loss record 8,467 of 9,037
  2.    at 0xD339953: calloc (in /usr/libexec/valgrind/vgpreload_memcheck-amd64-linux.so)
  3.    by 0xCB005AB: calloc (rtld-malloc.h:44)
  4.    by 0xCB005AB: allocate_dtv (dl-tls.c:370)
  5.    by 0xCB005AB: _dl_allocate_tls (dl-tls.c:629)
  6.    by 0xDE38616: allocate_stack (allocatestack.c:429)
  7.    by 0xDE38616: pthread_create@@GLIBC_2.34 (pthread_create.c:655)
  8.    by 0xDB2678E: ??? (in /usr/lib/x86_64-linux-gnu/libglib-2.0.so.0.8000.0)
  9.    by 0xDAEEB5E: g_thread_new (in /usr/lib/x86_64-linux-gnu/libglib-2.0.so.0.8000.0)
  10.    by 0xDAC9B29: ??? (in /usr/lib/x86_64-linux-gnu/libglib-2.0.so.0.8000.0)
  11.    by 0xE071FA5: ??? (in /usr/lib/x86_64-linux-gnu/libgio-2.0.so.0.8000.0)
  12.    by 0xE072064: g_task_get_type (in /usr/lib/x86_64-linux-gnu/libgio-2.0.so.0.8000.0)
  13.    by 0xE0DFAD8: ??? (in /usr/lib/x86_64-linux-gnu/libgio-2.0.so.0.8000.0)
  14.    by 0xE0D29D4: g_bus_get_sync (in /usr/lib/x86_64-linux-gnu/libgio-2.0.so.0.8000.0)
  15.    by 0x1182833D: ??? (in /usr/lib/x86_64-linux-gnu/gio/modules/libgvfsdbus.so)

In all 22 complaints there is only 1 single one, which contains at all lines of my sources:
Code: Text  [Select][+][-]
  1. 8 bytes in 1 blocks are definitely lost in loss record 408 of 9,037
  2.    at 0xD332828: malloc (in /usr/libexec/valgrind/vgpreload_memcheck-amd64-linux.so)
  3.    by 0x4445FC: CMEM_$$_CGETMEM$QWORD$$POINTER (in /hg/utis/azul)
  4.    by 0x7D2E09: PROPERTYSTORAGE$_$TCUSTOMPROPERTYSTORAGE_$__$$_SAVE (propertystorage.pas:536)
  5.    by 0x452F10: FORMS$_$TFORMPROPERTYSTORAGE_$__$$_FORMCLOSE$TOBJECT$TCLOSEACTION (customform.inc:3270)
  6.    by 0x44C5D1: FORMS$_$TCUSTOMFORM_$__$$_DOCLOSE$TCLOSEACTION (customform.inc:962)
  7.    by 0x4501AB: FORMS$_$TCUSTOMFORM_$__$$_CLOSE (customform.inc:2196)
  8.    by 0x52B300: AZUL1_$$_FORM1_CLOSE (azul1.pas:22091)
  9.    by 0x5169EB: AZUL1$_$TFORM1_$__$$_BUTTON_ENDECLICK$TOBJECT (azul1.pas:18111)
  10.    by 0x620285: CONTROLS$_$TCONTROL_$__$$_CLICK (control.inc:2911)
  11.    by 0x686399: STDCTRLS$_$TBUTTONCONTROL_$__$$_CLICK (buttoncontrol.inc:55)
  12.    by 0x686C50: STDCTRLS$_$TCUSTOMBUTTON_$__$$_CLICK (buttons.inc:169)
  13.    by 0x686265: STDCTRLS$_$TBUTTONCONTROL_$__$$_WMDEFAULTCLICKED$TLMESSAGE (buttoncontrol.inc:21)

The 2 referenced procedures are:
Code: Pascal  [Select][+][-]
  1. procedure TForm1.Button_EndeClick(Sender: TObject);
  2.    {Button "End" closes the program}
  3.    var stop: boolean;
  4.    begin
  5.    stop:=ask_vor_ProgEnde_stop; {asks if really wants to terminate}
  6.    if not stop then exit;       {if no}
  7.    Form1_Close; // this is line 18111
  8.    end;
  9.  
  10. procedure Form1_Close;
  11.    {closes the program}
  12.    begin
  13.    ask_in_FormCloseQuery:=false; {disable a query dialog in the OnClose Event}
  14.    Form1.Close; {closes the program} // this is line 22091
  15.    end;

The top most line in this complaint, wherefore a source line was found, is this procedure in <installdir>/lazarus/lcl/propertystorage.pas:
Code: Pascal  [Select][+][-]
  1. procedure TCustomPropertyStorage.Save;
  2. begin
  3.   if Active and not (csDesigning in ComponentState) then begin
  4.     StorageNeeded(False);
  5.     Try
  6.       if Assigned(FOnSavingProperties) then
  7.         FOnSavingProperties(Self);
  8.       try
  9.         SaveProperties;                       // this is line 536
  10.         FStoredValues.SaveValues;
  11.         NotifyLinks(poSave);
  12.         if Assigned(FOnSaveProperties) then
  13.           FOnSaveProperties(Self);
  14.         FSaved := True;
  15.       except
  16.         on E: Exception do
  17.         begin
  18.           if Assigned(FOnSaveException) then
  19.             FOnSaveException(Self, E.ClassName, E.Message);
  20.         end;
  21.       end;
  22.     Finally
  23.       FreeStorage;
  24.     end;
  25.   end;
  26. end;
I don't see how this can help me, because I get many complaints, which (except from 1 single one) contain not even 1 line of my sources, and in this single exception I can't find something wrong.

Example 3:
valgrind --leak-check=full --log-file=vg03.trc /hg/utis/azul
This time I played for 8 minutes with my program and used several features (when the AV occured 1 week ago, I had used the program for 83 minutes). The output of valgrind had > 2100 lines and ended with
ERROR SUMMARY: 1155 errors from 145 contexts
which is so huge, that this is not manageable, especially if after each very time consuming analysis I can't see a real bug.

Do I something wrong?

Of course I read https://wiki.freepascal.org/Debugging_with_Valgrind.
And I took a look at "valgrind --help" and "man valgrind" and https://valgrind.org, but in a reliable time it didn't help me.

As said, the AV last week occured during termination of the program after 83 minutes. Of course I can't remember, which features in what variantes or combinations or in which order I used and which error dialogs had been involved in which situations. I fear, that valgrind might find the root cause only, if
a) it's source position is really called again at all and
b) if all neccessary "conditions" are met.
And when the output of valgrind grows more and more when using my program longer - and most of it's complaints waste only time, because there is no bug - how should I find any real bug?

Of course it would be great to find the root cause for the AV, but because (until now) it occured only once after more than 1 year and "only" during the termination of the program, I don't want to spent too much time for it.

Has someone an idea of only adding some ingenious parameters for valgrind to reduce it's output to show only real bugs, which could cause an AV?
« Last Edit: September 07, 2025, 11:43:49 am by Hartmut »

jamie

  • Hero Member
  • *****
  • Posts: 7302
I am going to take a guess here.

You close the form directly from button.OnButtonClick I Believe is living on the same form?

 If you want to terminate the app then why not use the Application.Terminate? that steps the system through the
proper paces and the Form should still get the notification in the OnClose.

 You could also PostMessage a LM_CLOSE to the form which will arrive later after the Button has completed its event with the form.
   
  It's just an idea really.

 Jamie


The only true wisdom is knowing you know nothing

Hartmut

  • Hero Member
  • *****
  • Posts: 1000
Hi jamie,
TForm1.Button_EndeClick() is living in the same Form as Form1.Close(). I'm nearly 100% sure, that the bug is not caused at this button-click or at calling this Form1.Close(), but that the bug is caused somewhere in some "1000" lines which have been executed before.

Currently I want to find the bug which caused the AV. Not to change "something" in the hope, that it "possibly might" solve it. Because:
 - as long as the AV would not occur again, I would never know, whether it was solved or not solved.
 - and if it occurs again some day, then this action was for nothing and I lost all the time and had to dig into this issue completely again, after having forgotten most of the details, which I now have in my head.
 
 It would help me more, if someone could answer my questions about how to proceed with valgrind from reply #48.

Hartmut

  • Hero Member
  • *****
  • Posts: 1000
I had asked this:
Another question occured: when a Form has an OnClose Event handler an in it  'CloseAction:=caFree' is set: at which time will this Form be destroyed?
 - always immediately after the OnClose Event exits?
 - or can/will this be (always) "later", e.g. when the next Application.ProcessMessages() is called (by my code or from the LCL) or when certain "messages" are handled by the LCL?
 - what is the latest possibility, when this Form is destroyed?
 - is there a difference, if the Form is the MainForm?
 - is there a difference, if the Parent of the Form is var 'Application'?
 - is there a difference, if the Form was shown modal or non modal?

and got this answer from Thaddy:
Afaik it relies solely on Application.ProcessAsyncQueue and that works in FIFO order.

I did not find 'Application.ProcessAsyncQueue'. Not in https://lazarus-ccr.sourceforge.io/docs/lcl/forms/tapplication.html and not with google.

Maybe instead 'Application.ProcessAsyncCallQueue' was meant ???

Even if yes, this doesn't help me further. Because it's "documentation" in https://lazarus-ccr.sourceforge.io/docs/lcl/forms/tapplication.processasynccallqueue.html says only: "Calls all methods queued in QueueAsyncCall".
What is this and when is this processed?

I hope that someone else could answer my questions(s):
 - Because Thaddy's posts are typically as short as however possible and (for me) mostly incomprehensible.
 - And if he "only" wrote the wrong name, then he would "answer" my question(s) only by causing new questions.
 - And even if 'Application.ProcessAsyncCallQueue' would be correct - he was unsure - this would only tell, from where the Destroy() is caused, but I had asked when.
 - And he ignored my 3 last questions.
Maybe he is a genius and knows everything and can't imagine, that normal people (like me), do not know everything and need more information and details, than he writes (even if you ask him again multiple times). This is frustrating.

Please can someone else answer my questions(s). If 'Application.ProcessAsyncCallQueue' is correct, then I need some more detailed informations about
 - what this is
 - does a 'CloseAction:=caFree' in an OnClose Event handler insert a Destroy() command in this Queue?
 - when (at which time) is 'Application.ProcessAsyncCallQueue' called?
Thanks in advance.

Thaddy

  • Hero Member
  • *****
  • Posts: 18306
  • Here stood a man who saw the Elbe and jumped it.
If this takes four pages, you do something very wrong.
What it is, we don't know.

I give up, this is silly.
Due to censorship, I changed this to "Nelly the Elephant". Keeps the message clear.

Lutz Mändle

  • Jr. Member
  • **
  • Posts: 83
@Hartmut,
according to your first message in this thread your program is compiled with Lazarus 2.0.10 and FPC 3.2.0. I suggest to bring your project to an actual Lazarus (4.2 not 4.0), because maybe you chasing a ghost, an error that is long gone.

Lazarus 2.0.10 was released in july 2020.

Hartmut

  • Hero Member
  • *****
  • Posts: 1000
Thanks Lutz for your post. If the AV would be reproducible, then I would have tested my program with some other Lazarus versions to check, whether this makes a difference.

I thought about your suggestion switching to Lazarus 4.x, but I see these disadvantages:
 - as long as the AV would not occur again, I would never know, whether it was solved or not solved.
 - and if it occurs again some day, then the whole effort was for nothing and I lost all the time and had to dig into this issue completely again, after having forgotten most of the details, which I now have in my head.

And I've used 2.0.10 for too many programs to assume, that this AV comes probably from a bug in there. During many years I have found too many bugs in my sources, so the probability that the AV was caused from there, I guess to be considerable higher ;-)

Hartmut

  • Hero Member
  • *****
  • Posts: 1000
I think I found the reason for the AV!

My program uses a procedure fom a common unit which can display image files. This procedure sets an Event-Handler for 'Application.OnActivate' to a method of an internal class, but did not restore it before exiting. This means: after this procedure was called the 1st time, my program ran afterwards with Event 'Application.OnActivate' pointing to this internal class method. It's code was still in memory, so that was not the problem, but this method reads 1 class property and writes 2 class properties (2x 8 bytes) - but this class had already been free'd when the procedure had exited, so memory was written, which could be used meanwhile by others :-((

I'm very happy that I found this bad and very dangerous bug and did not stop too early searching for it.

Many thanks again to all who helped me. Again I learned a lot.

alpine

  • Hero Member
  • *****
  • Posts: 1410
I think I found the reason for the AV!
What is the guarantee that you found this exact bug? I would go further and set a trap to check if this is really happening. Like for example organizing a pool for this inner class and checking every time at the beginning of the method for a dangling Self in this pool.
"I'm sorry Dave, I'm afraid I can't do that."
—HAL 9000

Hartmut

  • Hero Member
  • *****
  • Posts: 1000
I would go further and set a trap to check if this is really happening. Like for example organizing a pool for this inner class and checking every time at the beginning of the method for a dangling Self in this pool.
Sorry, I don't understand. What do you mean with 'pool' here and how should I check for a dangling Self?

alpine

  • Hero Member
  • *****
  • Posts: 1410
I would go further and set a trap to check if this is really happening. Like for example organizing a pool for this inner class and checking every time at the beginning of the method for a dangling Self in this pool.
Sorry, I don't understand. What do you mean with 'pool' here and how should I check for a dangling Self?
You wrote that you problem is a call to procedure of object variable assigned to a method of a freed instance. Since the variable keeps the reference to the (freed?) instance to be passed as Self, you can check at the beginning of the method whether the Self is valid or dangling. For example you can keep track of the freed Self's into the destructor or instead of calling Free on instances, just to move them in a pool and later fetch'em when needed. Either way you should be able to check the validity of Self.
"I'm sorry Dave, I'm afraid I can't do that."
—HAL 9000

Hartmut

  • Hero Member
  • *****
  • Posts: 1000
Sorry alpine, I again don't really understand what you suggest to do and why this should be neccessary or recommendable. I guess I should do something in the OnDestroy-Event of the internal class... But in this OnDestroy-Event of this internal class I now restore the Event-Handler for 'Application.OnActivate', which I had changed at the beginning (and remembered). This seems to be sufficient sure for me.

 

TinyPortal © 2005-2018