FAQ FOR NEWSGROUPS: COMP.LANG.PASCAL.DELPHI.MISC, ALT.COMP.LANG.BORLAND-DELPHI

Version: 2006-09-16
First maintainer: Esther Michaels
Current maintainer: Maarten Wiltink (Evil miniFAQ Boss)
Posting schedule: Short version every Sunday, full version every first of the month

Copyright 2001-2006 the current maintainer, all rights reserved except the right to re-distribute the current document. Even better: give out the URL.


Latest version: http://www.bancoems.com/CompLangPascalDelphiMisc-MiniFAQ.htm
Plain text version: http://www.bancoems.com/CompLangPascalDelphiMisc-MiniFAQ.txt
Examples page: http://www.bancoems.com/mini_faq_examples.htm


CONTENTS

  1. How do I start another program from my program?
  2. How to stop a second instance of my program from executing? (Also: HPrevInst doesn't seem to work, why?)
  3. Floating-point work - i.e. with single, real, real48, double, extended - gives long decimals or wrong numbers. Why?
  4. Is there a limit on the number of characters allowed in a tMemo/tRichEdit?
  5. Why do I get an "abstract error" when I try to use a tStrings variable?
  6. How do I access a component/property/field of Form1 from Form2?
  7. How do I change the background, font, general appearance of an entry in a tListView, tTreeView, tListBox, tCombobox list, tStringGrid, etc.?
  8. How do I change the formatting of a line/word/character in a tMemo?
  9. Why does the debugger show my For loop variable counting down, not up?
  10. How do I get the path of my executable? And, how do I retrieve the command line parameters?
  11. When my program is in a loop it doesn't respond to user input or update its display. Can I change this?
  12. How do I access the compilation date in my program?
  13. How do I access the VersionInfo tab's data at runtime?
  14. Does Delphi have an equivalent to the VB Split function?
  15. I create a label/edit/some other control at run-time but it doesn't appear on the form. Why?
  16. How do I use streams?
  17. How do I declare an event handler for an object that I create at runtime?
  18. When using the TRegistry component under Windows NT, Windows 2000, or Windows XP, a user with less than Administrator rights is unable to access information stored in the HKEY_LOCAL_MACHINE hive. How can I work around this?
  19. When drawing text on a canvas, how do I determine the resulting text size?
  20. How can I loop through the components/labels/edit-boxes on my form? (Also: Tag is unused, what is it good for?)
  21. Can I pass objects to a DLL? (Also: Why does it say 'Cannot assign a TFont to a TFont'?)
  22. What compiler settings should I use, and where do I set them?

USEFUL LINKS


1. How do I start another program from my program?

The most common methods of doing this employ either ShellExecute or CreateProcess, both of which are documented in the WindowsSDK help file. ShellExecute is quite versatile and has the advantage of being simple and able to open or print any file for which there is a file association registered on the system. CreateProcess is a little more complex but provides much better control over the process. Information returned by CreateProcess can be used to pause a program until the called program has completed (using WaitForSingleObject). See http://www.bancoems.com/mini_faq_examples.htm for example code showing how to call each of these procedures.

Return to contents


2. How to stop a second instance of my program from executing? (Also: HPrevInst doesn't seem to work, why?)

HPrevInst only works in Delphi 1. There are several methods of handling this in Delphi 2 and above. The most common recommendation is to use a mutex (see the Windows SDK help). See http://www.bancoems.com/mini_faq_examples.htm for example code.

Return to contents


3. Floating-point work - i.e. with single, real, real48, double, extended - gives long decimals or wrong numbers. Why?

Because computers are finite, all floating point formats are approximations. Values that have no exact representation are simply replaced by the value closest to it. It's like replacing "1/3" by "0.3333", and the computer has no thoughts about what that number means. Multiplying it by 3 again gives 0.9999, not 1. Also, Trunc(0.9999) will return 0, not 1.

If, when rounding to two decimal places, the nominal pre-rounding decimal value is liable to be of the form X.yz5, note that of those, only X.125, X.375, X.625, and X.875 can be stored exactly, and are the only true half-way cases.

Comparing floating point numbers should not be done by testing for exact equality, but for a difference being smaller than the inaccuracy in the computed numbers. Errors start larger for shorter types and grow further as more calculations are performed with inexact numbers.

Testing for exact equality is appropriate when possible copies are compared. But this is not often; even assigning a literal constant to a variable in source loses precision as determined by the variable's type.

If you must have precision use the Currency type (4 decimals) or use an integer type and scale the results. When it's just a question of displaying a result, use one of the formatting functions that allow you to specify the number of decimal places to display - Format and FormatFloat. See http://www.efg2.com/Lab/Library/Delphi/MathInfo for more info on this and other math related questions.

Return to contents


4. Is there a limit on the number of characters allowed in a tMemo/tRichEdit?

Yes. The limit depends on the operating system and can be as low as 32KB. If you need to have more than 32KB in a memo, use a tRichEdit instead. Set the rich edit's PlainText property to True and its MaxLength property to an appropriately large value, e.g. RichEdit1.MaxLength := MaxInt - 2; allows the RichEdit1 to work with ~2GB. (Setting MaxLength to 0 as suggested for tCustomEdit in the help doesn't work for rich edits.)

Henry Bartlett bravely explained all the maddening details in a Usenet article.

Return to contents


5. Why do I get an "abstract error" when I try to use a tStrings variable?

You should never create a tStrings object. Instead create one of its descendants like tStringList.

Return to contents


6. How do I access a component/property/field of Form1 from Form2?

Add the Form1 unit to the Uses clause in the implementation section of Form2. (By default there is no uses clause so you may have to add one - do so just after the '{$R *.DFM}' line.) You can then reference items belonging to Form1 by prefixing them with 'Form1.', e.g., Form1.Label1.Caption := 'Hi there, I was set from Form2';

Return to contents


7. How do I change the background, font, general appearance of an entry in a tListView, tTreeView, tListBox, tCombobox list, tStringGrid, etc.?

You have to use the owner draw event (typically OnDraw<something>) to draw the items. This means that you have to draw each item when the control asks you to do so. See http://www.bancoems.com/mini_faq_examples.htm for example code.

Return to contents


8. How do I change the formatting of a line/word/character in a tMemo?

You can't. Use a tRichEdit instead.

Return to contents


9. Why does the debugger show my For loop variable counting down, not up?

The Delphi optimizer may generate loop code that decrements an internal counter instead of your variable. This behavior is guaranteed not to alter the correctness of your program. Ignore the debugger value and consider the For loop variable "unavailable due to optimization".

Return to contents


10. How do I get the path of my executable? And, how do I retrieve the command line parameters?

Application.ExeName will return the full name of your executable. You can get the path portion using ExtractFilePath. ParamStr(0) will return the same value as Application.ExeName. To retrieve other command line arguments use the ParamCount and ParamStr functions. See also FindCmdLineSwitch and CmdLine in the help.

Return to contents


11. When my program is in a loop it doesn't respond to user input or update its display. Can I change this?

Yes. In your loop you need to add a call to the Application.ProcessMessages method. This will allow your application to process Windows messages, including those generated by user actions. There are two significant caveats. First, since Windows messages often translate into calls to event handlers your program may begin to do things at inappropriate times. Make sure that the user can't initiate actions that will interfere with the loop while the loop is active. In particular, note the following sentence, taken from Delphi 3's help file on TApplication.Terminated: "For applications using calculation-intensive loops, call Application.ProcessMessages periodically, and also check Application.Terminated to determine whether or not to abort the calculation so that the application can terminate." The second caveat is that calling Application.ProcessMessages can be relatively expensive and may slow the program. In a fast (tight) loop you may not want to call the method on each iteration. If you only want to update the display and not handle user input you can use the Update method (Delphi 3 and up) of the control covering the part of the display you want to update. Remember that this will also slow down the loop!

Return to contents


12. How do I access the compilation date in my program?

There are a number of ways to achieve this, depending on the architecture of your program. If the program consists of a single executable whose creation date is guaranteed never to change after compilation, then the following code will be sufficient: DateToStr(FileDateToDateTime(FileAge(Application.ExeName))). This returns a string containing the date of the .exe file, formatted using the host computer's current date format setting. However, these circumstances don't hold for most programs. In these cases one solution is to create a file, perhaps called Today.pas, which holds a single constant: const COMPILE_DATE = '2001-11-17'; This file should be updated daily, perhaps at boot time. In units of your program which need to refer to the compilation date, you add the file to the "uses" clause, and then simply refer to the constant as you would any other. For example, an About box might contain a TEdit whose job is to display the compilation date: Edit1.Text := COMPILE_DATE; This will then show the compilation date in your About box.

Return to contents


13. How do I access the VersionInfo tab's data at runtime?

See http://www.bancoems.com/mini_faq_examples.htm for example code and a component that does this.

Return to contents


14. Does Delphi have an equivalent to the VB Split function?

There is no direct equivalent. However one can use the CommaText property of a tStrings to achieve the same result.

Example:

  procedure Split(const aString, Delimiter: string; Results: tStrings);
  begin
    Results.CommaText:='"' + StringReplace(aString, Delimiter, '","', [rfReplaceAll]) + '"';
  end;

(Note: the Results parameter is declared as tStrings. If you are using a variable as the actual parameter, (as opposed to a VCL control's property, e.g. tMemo.Lines, tListBox.Items, and tComboBox.Items), see question 5.)

Return to contents


15. I create a label/edit/some other control at run-time but it doesn't appear on the form. Why?

The most common cause of this problem is failure to assign, or correctly assign, the Parent property. When one creates a control at run-time the Owner (passed as a parameter to the constructor) should in almost all circumstances be the form. Once the control has been constructed one must then assign it a Parent. In most circumstances the Parent should also be the form. However, if one wants the control to be on a Panel or in a GroupBox then the Panel/GroupBox control should be made the Parent.

Return to contents


16. How do I use streams?

Alan Lloyd has written an excellent introduction to streams in the form of a help file, available from http://www.bancoems.com/mini_faq_examples.htm.

Return to contents


17. How do I declare an event handler for an object that I create at runtime?

Declare the event handler with the appropriate type signature (e.g. an OnClick handler will be of type TNotifyEvent), then once you have created the object simply assign the handler to the OnClick property of the object, like this: MyRuntimeButton.OnClick := MyRuntimeButtonClickHandler; See the examples file at http://www.bancoems.com/mini_faq_examples.htm for an example.

Return to contents


18. When using the TRegistry component under Windows NT, Windows 2000, or Windows XP, a user with less than Administrator rights is unable to access information stored in the HKEY_LOCAL_MACHINE hive. How can I work around this?

The problem is caused by the fact that TRegistry (and the derived TRegIniFile) always opens a key with KEY_ALL_ACCESS privileges, even if only KEY_READ would be needed.

In Delphi 5+, you can specify the access you require using the Access property.

You can also avoid this by going back to using the WinAPI registry functions (RegOpenKey et. al.), or in Delphi versions that don't already have it, add an Access property to a new class derived from TRegistry. Alternatively, the new class could just always open keys read-only.

Return to contents


19. When drawing text on a canvas, how do I determine the resulting text size?

Create a bitmap and allocate a font to its canvas. To get the height of the font elements, call the WinAPI function GetTextMetrics using the bitmap's handle. Use TCanvas.TextWidth to get character widths. Some printing terms are used in GetTextMetrics:

So the vertical margins in a TEdit are TEdit.Height - (Ascent + Descent), but this dimension is neither constant nor the same as External Leading.

All values from GetTextMetrics will be in pixels. A call to GetDeviceCaps can tell you how many pixels there are in an inch on your output device.

Return to contents


20. How can I loop through the components/labels/edit-boxes on my form? (Also: Tag is unused, what is it good for?)

Loop through the Components array property of the form. To process only one kind of component, test the class of each using the "is" operator. To indicate special processing for any particular component, you can set its Tag property in the Object Inspector.

If you use Tag to signify that a component should be treated specially in your loop, use zero to mean that it should be ignored, to prevent surprises later when you may add components to the form. Tag is declared as LongInt and its default value is zero. If a 4-byte LongInt is not enough for your purposes, you can store an object reference or a pointer to a record in it, but then be careful that you know what you are doing.

See http://www.bancoems.com/mini_faq_examples.htm for example code.

Return to contents


21. Can I pass objects to a DLL? (Also: Why does it say 'Cannot assign a TFont to a TFont'?)

Yes, you can, but there's a catch. The DLL will not use the same classes as the main program even when compiled from the same source. Objects will look the same, but their classes will not compare equal. That's why assigning a TFont value from the DLL to a TFont property in the main program (or the other way around) doesn't work: the Assign procedure is looking for the main program's TFont class, and never recognises the DLL's TFont object.

Using packages instead of normal DLLs solves this problem. Packages use the main program's classes. This is the preferred solution.

Return to contents


22. What compiler settings should I use, and where do I set them?

From the menu, select Project/Options, and pick the Compiler tab.

For debugging, turn all runtime error checking on, all messages on, and almost all debug information on. Using Debug DCUs is optional. Turn Optimization off.

In release code, range checking and overflow checking are still valuable.

All the options can also be set or cleared in the code using compiler directives. These then override the active settings from that point down. Combined with conditional compilation, this lets you use different settings in different cases without having to change the IDE's global settings each time.

Return to contents


Links

These links may prove useful. Inclusion here should not necessarily be taken as an endorsement.

Newsgroups Etiquette
http://www.uwasa.fi/~ts/http/tsfaq.html
http://ietf.org/rfc/rfc1855.txt
http://en.wikipedia.org/wiki/Netiquette
How to ask questions to maximum effect
http://www.catb.org/~esr/faqs/smart-questions.html
Borland Delphi Newsgroups
http://newsgroups.borland.com/cgi-bin/dnewsweb?cmd=listall&group=borland.public.delphi.&utag= (but first read the posting guidelines, at http://info.borland.com/newsgroups/guide.html)
Google - Newsgroups archives
http://groups.google.com/groups?hl=en&lr=&safe=off&group=comp.lang.pascal.delphi.misc
http://groups.google.com/
The Delphi Bug List - bugs and gotchas
http://www.jrsoftware.org/buglist/bugsall.htm
Deborah Pate's Pages - Word, Excel, etc. automation
http://www.djpate.freeserve.co.uk/Automation.htm
Kyle Cordes BDE Alternatives Guide
http://www.kylecordes.com/bag/index.html
Delphi Printing Info and Links
http://www.efg2.com/Lab/OtherProjects/PrinterProjects.htm
Microsoft MSDN - Win API documentation
http://msdn.microsoft.com/
Project JEDI - open source code library
http://www.delphi-jedi.org/
Delphi Super Page (DSP) - components, links
http://delphi.icm.edu.pl/
Torry's Delphi Pages - components, links
http://www.torry.net/
ICS (Internet Component Suite) - internet components
http://www.overbyte.be/frame_index.html?redirTo=/products/ics.html
Indy (Internet Direct, was Winshoes) - internet components
http://www.nevrona.com/Indy
Timo Salmi's Pascal programming material (a little dated but good general Pascal knowledge)
http://www.uwasa.fi/~ts/http/http2.html#programming
Martin Harvey's tutorial on multi-threading
http://codecentral.borland.com/Item.aspx?id=14809
Henry Bartlett's page on Delphi-related newsgroups
http://www.hotkey.net.au/~hambar/habit/newsgroups.htm
Paul Breneman's page on the TurboPower open source libraries
http://www.turbocontrol.com/TPSupport.htm
Gary Darby's Delphi for fun
http://www.delphiforfun.org/
Rob Kennedy's Delphi Q&A
http://www.cs.wisc.edu/~rkennedy/

VERSION HISTORY

2006-Sep-16:
Added Q21 (with thanks to Rob Kennedy, Bjørge Sæther, and Jamie) and Q22 (with thanks to John Stockton and Bruce Roberts). Added yet another paragraph to Q3 (with thanks to John Stockton). Added to Q4 (with thanks to Henry Bartlett). Put links on the newsgroup names (with thanks to John Stockton). Updated Links section (with thanks to Paul Breneman, Bruce Roberts, Martin Harvey, Henry Bartlett, Tom, Paul Schoen, and Jerry French whose suggestion actually didn't make it in). Modified Q2 sample code (with thanks to David Reeve, Bruce Roberts, Rob Kennedy, and Laura Blake).
2004-May-31:
Removed link to Tutorial Times (with thanks to Henry Bartlett). Added link to Eric Raymond's page on asking questions the smart way (with thanks to Martin Strand). Added a paragraph to Q3 (with thanks to John Stockton). Updated copyright notice (with thanks to Bruce Roberts).
2003-Oct-07:
Updated copyright notice (with thanks to John Stockton).
2003-Sep-21:
HTML tidied. Added copyright notice. Removed dead link from Q12. Rephrased Q20.
2003-Jul-29:
Eample date in Q12 changed to an unambiguous value. Reordered and slightly changed Q18. Rephrased Q19 and added note about units.
2003-Jun-27:
Rephrased Q3, again. Added Q18 (with thanks to Dan Donoghue), Q19 (with thanks to Alan Lloyd), and Q20 (with thanks to Henry Bartlett). Added a link to Henry Bartlett's Delphi newsgroups page. Reordered document. Removed introduction.
2002-Nov-16:
Rephrased Q3.
2002-Jul-27:
Reformatted into HTML.
2002-May-10:
Minor corrections, added links to Borland Delphi newsgroups and posting guidelines.
2002-Apr-21:
Added Q17.
2002-Apr-11:
Minor corrections, added link to Martin Harvey's multi-threading tutorial.
2002-Apr-06:
Added Q16 (with thanks to Alan Lloyd for the referenced file)
2002-Jan-13:
Added Q14 and Q15 (with thanks to Bruce Roberts), and updated introduction to fit with abbreviated-posting policy.
2001-Nov-22:
Added Q13 (with thanks to Daniel Rutten).
2001-Nov-11:
Added Q12 (with thanks to John Stockton).
2001-Oct-30:
Updated Links section.
2001-Apr-26:
Added reference to FindCmdLineSwitch and CmdLine in Q10.
2001-Apr-25:
Formatted to 80 characters per line, added preamble, made html version.
2001-Apr-04:
Initial version (kindly contributed by Bruce Roberts).

END