FAQ: comp.lang.pascal.delphi.misc miniFAQ (full version)

From: Evil miniFAQ Boss (miniFAQ_at_mfw.dds.nl)
Date: 03/01/05

  • Next message: Maarten Wiltink: "Re: Convert C-Builder program to Delphi?"
    Date: 01 Mar 2005 02:59:25 GMT
    
    

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

    Version: 2004-05-31
    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-2004 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?
    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?)

    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.

    --------------------------------------------------------------------------------

    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.

    --------------------------------------------------------------------------------

    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.

    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.

    --------------------------------------------------------------------------------

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

    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.)

    --------------------------------------------------------------------------------

    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.

    --------------------------------------------------------------------------------

    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';

    --------------------------------------------------------------------------------

    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.

    --------------------------------------------------------------------------------

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

    You can't. Use a tRichEdit instead.

    --------------------------------------------------------------------------------

    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".

    --------------------------------------------------------------------------------

    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.

    --------------------------------------------------------------------------------

    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!

    --------------------------------------------------------------------------------

    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.

    --------------------------------------------------------------------------------

    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.

    --------------------------------------------------------------------------------

    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.)

    --------------------------------------------------------------------------------

    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.

    --------------------------------------------------------------------------------

    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.

    --------------------------------------------------------------------------------

    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.

    --------------------------------------------------------------------------------

    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. Alternatiely, the new
    class could just always open keys read-only.

    --------------------------------------------------------------------------------

    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:

    * Ascent is the pixel height of characters, including any diacritics,
      above the base height.
    * Descent is the pixel amount below the baseline, in letters like "y" and "g".
    * Internal leading (pronounced "ledding") is how much higher diacritics go
      than capitals.
    * External leading is the minimum empty space between two lines above
      each other: between descent for the top line and capitals or diacritics
      for the bottom line.

    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.

    -----------------------------------------------------------------------------

    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 in, but then be careful that you know what you are doing.

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

    --------------------------------------------------------------------------------

    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
    How to ask questions to maximum effect
            http://www.catb.org/~esr/faqs/smart-questions.html
    Borland Delphi Community - TI, FAQ, links, articles
            http://community.borland.com/delphi/0,1419,1,00.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://www.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
    Undu - Delphi articles, tips, techniques, links
            http://www.undu.com/
    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
    BDE Support Page
            http://www.bdesupport.com/
    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/
            http://community.borland.com/homepages/dsp
    Torry's Delphi Pages - components, links
            http://www.torry.net/
    ICS (Internet Component Suite) - internet components
            http://overbyte.delphicenter.com/frame_index.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://www.pergolesi.demon.co.uk/prog/threads/ToC.html
    Henry Bartlett's page on Delphi-related newsgroups
            http://www.hotkey.net.au/~hambar/habit/newsgroups.htm

    --------------------------------------------------------------------------------

    VERSION HISTORY

    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: Example 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


  • Next message: Maarten Wiltink: "Re: Convert C-Builder program to Delphi?"
  • Quantcast