Delphi RSS Resources, Delphi Components, Delphi Sites, Articles, Dynamic XML Feeds, Tutorials, Sources
 
 
 
Google
 
Web delphirss.com
| Server-Scripts.com | Informations for JAVA | Informations for PHP | SEO Web Links | Borland Delphi
 

Data types

25.55 becomes to 24.5499999 in a field of a calculated paradox-field
Array of const
Create 'dynamic' array
Static Variables
Dynamic Components Solution
Class/Static/Shared Variables
Creating many instances
Difference of TMemoFields
Using integer pointers
MS Binary Format / IEEE conversion
Array of the Image Object
Pass a record problem
Function pointer
Converting Real to a fraction of two integers
Resizing (Dynamic) Arrays
Use Free with records
Create large arrays
Pointer to a function
Pass a function as a parameter
Array of TPoints
Function return type


25.55 becomes to 24.5499999 in a field of a calculated paradox-field

Question

Why 25.55 become 24.499999?
I have a paradox table that contains currency values. I am trying to
calculate totals for some of the fields programmatically with the
following code:

 Table1.Open;
   Table1.first;
   VATTotal := 0;
   SalesIncVAT := 0;
   While not Table1.EOF do
     begin
       VATTotal := VATTotal + Table1VAT.value;
       SalesIncVAT := SalesIncVAT + Table1GrandTotal.value;
       Table1.next;
     end;
     Label2.caption := FloatToStr(SalesIncVAT);
     Label3.caption := FloatToStr(VATTotal);
     Label1.caption := FloatToStr(SalesIncVAT - VATTotal);

Answer

A:
The label captions all show the same type of answer as the subject
line.  Can someone explain what I've done wrong.

You're not to blame for the calculation error!

I've found the same type of problems in an accounting package I'm writing
(=serious!).
Seems to me that Borland has some calculating coding to do.

You can get around the problem using the round function.
SalesIncVAT:=round(SalesIncVAT*100)/100;  {gives you two decimal places}

A:
that's nothing extraodrinary, this is a basic property of floating point
math, which is precise only to a given number of decimal digits. More
specifically float is precise for intermediate range integers and for
fractions which are a sum of components which are powers of 2, any other
number is rounded at the float accuracy (7 digits for single precision, 15
for double, 20 for extended). One has to use round or the str procedure:
var
  s : string;
begin
  str(SalesIncVat:10:2,s); {10 characters altohether (with point) and 2
			    decimal digits}
  Label1.Caption:=s;

A:
In the help it is written that FloatToStr formats the string with 15 decimal
digits - that is why your number is displayed in a fancy fashion, try this
function with a number like 25.5, 25.25, 25.125 or so i.e. one that has a
finite representation in binary notation and you should get it back.

Or use the function FloatToStrF which takes also specification of total
width and number of decimal digits as its arguments.


Array of const

Question

InsertRecord() takes an array of const.  How do I build an array of const
at runtime?

Answer

A:
procedure foo(a : array of const);
implementation
 var
     var1      : longint;
     var2      : pointer;
     var3      : integer;
begin
     var1 := 12345678;
     var2 := @var1;
     var3 := 1234;
     foo([var1, var2, var3]);

Actually an array of const is more correctly called array of tvariant.
Tvariant is a multiple choice kind of variable that can take an number of
types. It has its heritage in Visual Basic. Delphi allows to use either name.

A:
Define a type such as:

TYPE
  NAME1 = Array[1..4,1..10] of Integer;

Then, in your CONST section:

NAME2 : NAME1 = ((1,2,3,4,5,6,7,8,9,10),
                 (1,2,3,4,5,6,7,8,9,10),
                 (1,2,3,4,5,6,7,8,9,10),
                 (1,2,3,4,5,6,7,8,9,10));

Create 'dynamic' array

Question

How do I create a 'dynamic' array?  I need to vary the number of elements
in the array at run-time.

Answer

A:
Assuming you want to store "GIZMOS" in your array, try the following:
CONST
  MaxGIZMOS = $FFFF Div (SizeOf(GIZMOS)) { Or whatever the maximum number of
GIZMOS is going to be...}

TYPE
  pGIZMOArray = ^GIZMOArray;
  GIZMOArray  = Array[1..MaxGIZMOS] of GIZMOS;

VAR
  TheGIZMOS: pGIZMOArray;
  GIZMOcount: integer;
BEGIN
  GetMem(TheGIZMOS,(GIZMOcount+1)*SizeOf(GIZMO)); {Need 1 extra as GetMem
array is zero-based...}
  TheGIZMOS^[index] := Whatever;
etc...

A:
TList is such a dynamic array. Look for details in the Help section. If you
want to do it yourself you have to use GetMem to allocate a pointer to dynamic
memory and later FreeMem to release the space of the dynamic array. Tlist does
all that for you in a painless way.

Static Variables

Question

Does DELPHI allow static variables? Static, in the C sense, a variable declared
in a procedure that does not disappear when the procedure is exited, and is
available when the procedure is next entered.

Answer

A:
Yes, it does. You have declare the variable in the const section,
for example.

procedure P;
const
  MyVariable : Integer = 0;
begin
  Inc(MyVariable);
end;

In this example MyVariable holds the P calls number.

  However, often it is a better to use the field of the object instead
(if possible).


Dynamic Components Solution

Question

How to dynamic component creation?

Answer

A:
Warning to Newbies:
If you simply want to create a component whos type you know at compile time
then you should read the delphi\doc\VB2Delph.wri file to see how this is done,
it also explains control arrays and is just darn good reading anyway. This post
explains how to utilise the RTTI facilities in Delphi.

The first thing that your application needs to do is register all the classes
that you know you are going to need create at some stage in your program. This
can be done using either the RegisterClass(), RegisterClasses() or
RegisterClassAlias() functions.

eg.
    procedure TForm1.FormCreate(Sender: TObject);
    begin
        RegisterClasses([TButton, TEdit, TMemo, TLabel]);
    end;

This may seem like a limitation but then Delphi is a static language. If you
want true dynamic creation of objects in a weakly typed late bound environment
then use a dynamic language like Smalltalk. I have a feeling that Delphi uses
this registration mechanism to register all the components in the DCL when it
starts up, which allows it to create any component at design time.

Creating the components. Use the FindClass() function to return a class
reference to the component that you want to create and call its Create method.
Easy, isn't it? In the example I have typecast SomeComponent to a TControl so
that I can set its parent property (I can do this because I know that all the
classes that I registered were descendants of TControl). You need to set the
parent property of a control to make it appear on the form.

eg.

    procedure TForm1.CreateClick(Sender: TObject);
    begin
        SomeComponent:= TComponentClass(FindClass(ClassName.Text)).Create(Self);
        (SomeComponent as TControl).Parent := Self;
    end;

Now that you have the component, how do you set it's properties without using
the biggest case statement in the universe? Use the GetPropInfo() function to
get the run-time type information (RTTI) structure for the property, and then
use the SetXXXXProp() set of functions to set it's value. (Note: These
functions are not documented in the Delphi help files. OO programming means
reading other peoples code and building on it, not reinventing the proverbial
wheel.) Each SetXXXXProp() function also has an equivalent GetXXXXProp()
function so you can inspect an objects property values.

eg.

    procedure TForm1.SetPropertyClick(Sender: TObject);
    var
        PropType: PTypeInfo;
        PropInfo: PPropInfo;
    begin
        PropInfo := GetPropInfo(SomeComponent.ClassInfo, PropertyName.Text);
        PropType := PropInfo^.PropType;
        case PropType^.Kind of
            tkInteger:
                SetOrdProp(SomeComponent, PropInfo,
StrToInt(PropertyValue.Text));
            tkChar:
                SetOrdProp(SomeComponent, PropInfo, Ord(PropertyValue.Text[1]));
            tkEnumeration:
                SetOrdProp(SomeComponent, PropInfo, GetEnumValue(PropType,
PropertyValue.Text));
            tkFloat:
                SetFloatProp(SomeComponent, PropInfo,
StrToFloat(PropertyValue.Text));
            tkString:
                SetStrProp(SomeComponent, PropInfo, PropertyValue.Text);
        end;
    end;

You can also set the values of Set, Class and Method properties but this can be
a little bit more complicated. I might post how to do that a little bit later.

And that's it. It's pretty amazing what you can find out by reading the VCL
source code.

This is tempting feature, but has potential for mass abuse. There is no
substitute for a good understanding of the other ways of achieving the same
things in Delphi and choosing the technique most appropriate to your design.

Class/Static/Shared Variables

Question

I have been generally pleased with Delphi's level of Object Orientation,
but it does seem to be missing Class Variables.  It would be nice to be
able to have a class/static/shared variable that gets updated every time
the class is instantiated - like so:

type
    TNode = class
    public
        NodeCount : Integer = 0;  {THIS IS NOT ALLOWED}
        constructor Create;
        {
        other stuff
        }
    end;

    TNode.Create;
    begin
        inherited Create;
        Inc(NodeCount);
    end;


It seems the compiler won't allow the typed constant within a class type
declaration.  So the NodeCount variable gets reinitialized for every
instantiation of the TNode class.  It will work by putting the class
variable OUTSIDE of the type statement as a plain-old typed constant.


But then rather than having OOP looking code like:
        SampleNode := TNode.Create;
        x := SampleNode.NodeCount;

You have to resort to semi OOP/procedural code like:
        SampleNode := TNode.Create;
        x := NodeCount;

Answer

A:
It's not a big deal to get equivalent
functionallity by using a class method. You simply declare NodeCount as
a regular typed constant in the implementation section of your file.


type
    TNode = class
    public
        NodeCount : Integer = 0;  {THIS IS NOT ALLOWED}
        constructor Create;
        Class Function GetNodeCount : word;
        {
        other stuff
        }
    end;

implementation
const
     NodeCount : word = 0;

    TNode.Create;
    begin
        inherited Create;
        Inc(NodeCount); 
    end;

    Function TNode.GetNodeCount : word;
    begin
       result := NodeCount;
    end;



So your code will look just as you want:
        SampleNode := TNode.Create;
        x := SampleNode.GetNodeCount;


the follwing form is also legal:
        x := TNode.GetNodeCount;

Creating many instances

Question

How do I create many intances of an object. Sometimes I need to create
10 or so instances and sometime I need 1000 instances. How should I
do it if I have an object named TSSObject.

        TSSObject = class(TObject)
              n1 :Single;
              n2 :Single;
        end;

Answer

A:
list:=Tlist.create;
For i:= 1 to 1000 do
    begin
    SSObject:=TSSObject.create;
    {put the newly created object somewhere - eg on a Tlist}
    list.add(SSObject);
    end;

Difference of TMemoFields

Question

While I'm on the subject can someone please explain to me why this doesn't
work! I'm afraid I just don't understand pointers all the time.

procedure TForm1.Button1Click(Sender: TObject);
var
  Buffer: Pointer;
  MyStrings: TStringList;

begin
  MyStrings := TStringList.Create;
  GetMem(Buffer, Table1Notes.DataSize);
     {After this call Pointer's Addr becomes nil?}

  Table1Notes.GetData(Buffer); {Of course this doesn't work, Pointer is nil }

  FreeMem(Buffer, Table1Notes.DataSize);
  MyStrings.Free;
end;

Answer

A:
First, if the size argument to GetMem is zero, GetMem will set the pointer
to nil (not leave it the way it was, but actually assign nil to it).  Might
want to check the value of DataSize (or getTextLen) in your debugger before
the call.

(Ignore this paragraph if Table1Notes is not a memo.)
Second, if Table1Notes is a memo field, you probably want to use
Table1Notes.getTextLen, not DataSize, since DataSize gives you the length of
the record buffer segment (0-254) while getTextLen gives you the actual size
of the memo.  (For a string field, DataSize will work, but then it's curious
as to why it's zero.)  Also, might want to consider getTextBuf rather than
getData, don't exactly know why, but I played around with them awhile ago
and getTextBuf seemed to work while getData didn't.

A:
Since wordwrapping is your application, you can just replace the #10 (line
feed) and #13 (carriage return) characters with spaces, eg.

   cursor: pchar;

   cursor := your buffer;
   while cursor^ <> #0 do
      if (cursor^ = #13) or (cursor^ = #10) then cursor^ := ' ';

This is easy because we don't have to move any text around, although it does
mean there'll be two blanks at the end of each line, which shouldn't matter
since you're word wrapping anyway.  Alternatively, you can change them to
some special character that your word wrapper recognizes as a word break but
otherwise discards (eg. #8).  If you need to get rid of them, use two
cursors as follows (OTTOMH, not tested):

   out, in: pchar;

   out := your buffer;
   in := out;
   while in^ <> #0 do begin
      if (in^ <> #10) and (in^ <> #13) then begin
          out^ := in^;
          inc (out);
      end;
      inc (in);
   end;
   out^ := #0;

A:
If you instead want to replace every CR-LF pair or a single CR or LF with a
single space you could use this:

  out, inn: PChar;

  out := your byffer;
  inn := out;
  while in^ <> #0 do begin
    if (in^ = #10) then begin
    end
    else if (in^ = #13) then begin
      if (in+1)^

A:
If you instead want to replace every CR-LF pair or a single CR or LF with a
single space you could use this:

  out, inn: PChar;

  out := buf;
  inn := out;
  while inn^ <> #0 do begin
    if (inn^ = #10) or ((inn^ = #13) and ((inn+1)^ <> #10)) then begin
      out^ := ' ';
      Inc(out);
    end
    else if (inn^ = #13) then
      { CR alone - ignore }
    else begin
      out^ := inn^;
      Inc(out);
    end;
    Inc(inn);
  end;
  out^ := #0;
  { buf is now massaged }

Untested is: the effect of shortening (by way of setting the #0 terminator)
this PChar - safest to use compile time arrays or GetMem'ed buffers, what
would happen using StrAlloc/StrDispose?

A:
Here is
the final code after some small changes! For example, at the end, we needed
to tell the pointer to go back to the beginning of its new string.

procedure TForm1.RemoveSpaces(var InBuf: PChar; Size: Word);
var
  Input,
  OutPut,
  Orig: PChar;
begin
  GetMem(Output, Size);
  input := Inbuf;
  Orig := Output;
  while input^ <> #0 do
  begin
    if (input^ <> #10) and (input^ <> #13) then
    begin
      output^ := input^;
      inc (output);
    end;
    inc (input);
  end;
  Output^ := #0;
  Output := Orig;
  InBuf := Output;
end;

I still wonder about that darn GetData thing! I would still like to not have
to use a TMemo! If Anyone out there can solve this problem I'd be very
greatfull! I'd give you a complimetary first hand look at my new printing
rountines! That's what this whole mess is for anyhow! So far I have implemented
text output in any font at any position in inches, and all that basic stuff!
But what I think is really cool, Is my dynamic grid! You can create a grid of
any number of rows and column. Assign text to and cell, setting its Horizontal
AND Vertical Justification, Select border style for each cell and many ways to
manipulate and print these!

Using integer pointers

Question

var
  myptr: PInteger;
begin
  GetMem(myptr, 10);
   (myptr + 1)^ := 1;       { How can I do this? }
  FreeMem(myptr, 10);
end;

Answer

A:
You would have to create the type first.

Type
	Pinteger : ^Integer;

Var
	MyPtr : Pinteger;

Possibly you have used a bad example but it does not seem to make sense to
use a (32 bit) pointer for a 16 bit value or to allocate 10 bytes for the
variable.

Pascal allows you to use NEW and DISPOSE which automatically allocates and
de-allocates the correct size block.

ie NEW(MyPtr) = GetMem(MyPtr, Sizeof(MyPtr)).

Presumably you wish to do a calculation on a variable number of integers.
In that case have a look at TList in the help. Better yet use a linear
array (or a pointer to one if there could be enough elements to make memory
an issue).

A:
For completeness, this should be

  NEW(MyPtr) = GetMem(MyPtr, SizeOf(MyPtr^));

SizeOf(MyPtr) will always be 4 bytes, as 16 bit pointer.

If I understand what you want, a dynamic array of integers, since you know
how many you want at runtime, you could also do

Type
  pIntArr = ^IntArr;
  IntArr  = Array[1..1000] of Integer;
Var
  MyPtr : pIntArr;
Begin

  GetMem(MyPtr, 10); { 10 = SizeOf(Integer) * 5  !!)
{  MyPtr[2]:=1; }
<<<< My turn to be incomplete !! >>>>
  MyPtr[2]^:=1;

  FreeMem(MyPtr,10);
End;

A:
It looks like Delphi makes a special case of pchar.  Best I could figure out
that would let you use the syntax you want is:

type
   intarray = array[0..20000] of integer;

procedure TForm1.Button1Click(Sender: TObject);
var
   xptr:  ^IntArray;
begin
   GetMem(xptr, 10);
   xptr^[idx] := 1;  { where idx is 0 to 4 since we have 10 bytes = 5 integers }
   FreeMem(xptr, 10);
end;

Note that you don't really need to allocate an array of 20,000, but Delphi
range checking won't work unless it is 20,000.  (Pointer users caveat
emptor!)

MS Binary Format / IEEE conversion

Question

Couple of questions:
1.  Does Delphi store real numbers in "Microsoft Binary Format" or "IEEE"?
2.  How can I call a small segment of assembler code within my Delphi code?
Can I embed assembler routines within Delphi?  Please note my assembler
exposure is very limited, but I have also wondered how I can do this, in
both C and now Delphi.

Answer

A:
"whatever the base-level machine uses" is not so straightforward before
Intel's 80x87 numeric coprocessors came along.  I'm not sure if the 80x86
processors had any native instructions to perform floating point
arithmetic.  This could be why Microsoft created their own proprietary
format for floating point numbers; they had to do all the arithmetic
themselves, using their own runtime library.  Today, the 80x87 makes the
arithmetic automatic, and IEEE is now the standard.

Delphi does store the following floating point types in IEEE format:
  Single      4 bytes
  Double      8 bytes
  Extended   10 bytes

Note that Real (6 bytes) is not on this list.  I may be wrong, but I
believe Real is an intrinsic Pascal type; its existence may predate the
80x87.

[Aside:  Delphi's online help says that, by default (via the $N+ compiler
directive), the compiler will generate code to perform ALL floating point
calculations using 80x87 instructions, including Real types.  So either the
compiler will generate calls to a runtime library to handle Real types, or
else I am completely wrong about the above! :) ]

Anyway, in checking Visual Basic's online help, I see that its data types
also include Single and Double, which are also IEEE, and are identical to
Delphi's Single and Double types.  However, there is no mention of
"Microsoft Binary Format".

I then dropped down to DOS and ran QBasic, which is Microsoft's old
QuickBasic interpreter that is now included in DOS.  If you check its
online help, you will see the following:

=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
MKSMBF$ and MKDMBF$ convert IEEE-format numbers to Microsoft-Binary-format
numeric strings that can be stored in FIELD statement string variables.
CVSMBF and CVDMBF convert those strings back to IEEE-format numbers.

MKSMBF$(single-precision-expression!)
MKDMBF$(double-precision-expression#)
CVSMBF (4-byte-numeric-string)
CVDMBF (8-byte-numeric-string)

   Function    Returns
   ========    ============================================================
   MKSMBF$     A 4-byte string containing a Microsoft-Binary-format number
   MKDMBF$     An 8-byte string containing a Microsoft-Binary-format number
   CVSMBF      A single-precision number in IEEE format
   CVDMBF      A double-precision number in IEEE format

   These functions are useful for maintaining data files created with
   older versions of Basic.
=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=

So, to sum up, if you want to access your "MetaStock" files, I think you
have 3 choices.

1.  Write your program in QBasic/DOS

2.  Find substitutes (hopefully compatible with Delphi) for the conversion
    functions mentioned above.

3.  Write these functions yourself.  You will have to find documentation
    for the bitwise layout of the old "Microsoft Binary Format" Single and
    Double types, perhaps in MS's old Basic manuals.

Array of the Image Object

Question

How do I implement an array of objects...lets say I want 10 image
controls on my form, but don't want a different name for each one...in
VB there was an index property...how do I do it in Delphi?

Answer

You cannot do this visually & straight off, but if you don't mind some coding
this is pretty simple:

type
  TForm1 = class(TForm)
    ...
  public
    images: array [1..10] of TImage;
    ...
  end;

procedure TForm1.FormCreate(...);
var i: integer;
begin
  ...
  for i := 1 to 10 do begin
    images[i] := TImage.Create(self);
    with images[i] do begin
      parent := self;
      tag := i; { makes it easier to detect e.g which 
      ... set other properties as required, e.g:
      OnClick := MyClickEventHndlr;
    end;
  end;
  ...
end;

To make sure you get all "uses" correct you may drop one such dynamic component
on your form, and then either delete it or set visible to false.

A more elaborate way is of course to design your own component to do the same.

Pass a record problem

Question

I have a Delphi application that has about two dozen simple type
declarations similar to the following:

type RecordA = record
  this             : Integer;
  that            : String;
  the_other : Integer;
end;

Each record type can have an essentially random number of fields in it.
I'm looking for a way to write a *generic* function that can be passed
a specific record variable and a 'field number' which will be able
to determine the name of the field, it's type and it's value.

A rough example:

recA    :  RecordA;
.....
recA.that  := 'Steve';
MyFunc(recA, 2);   { Give me details on the 2nd field in recA };

function MyFunc(rec: ????;  field : Integer);
begin
  { Do some magic }

  Label1.Caption := recordname;      { 'recA' }
  Label2.Caption := fieldname;           { 'that' }
  Label3.Caption := _type;                    { 'String' }
  Label4.Caption := value;                    { 'Steve' }
end;

Answer

A:
An idea, may not be what you're looking for, but here it is:

Define a base class, call it allrecs, eg.

   tAllrecs = class
      function getVal (field: integer): string; virtual;
   end;

Then derive a class for each record type, eg.

   recA = class (tAllrecs)
      this             : Integer;
      that            : String;
      the_other : Integer;
      function getVal (field: integer): string; virtual;
   end;

then for each class's function define what it returns:

   function recA.getVal (field: integer); string;
   begin
      case field of
         1: getVal := intToStr (this);
         2: getVal := that;
         3: getVal := intToStr (the_other);
      end;
   end;

Then you can define 

   function myFunc (rec: tAllrecs; field: integer);
   begin
      label2.caption := allrecs.getVal(field);
   end;

and you can then call myFunc with any class derived from tAllrecs, eg.
   myFunc (recA, 2);
   myFunc (recB, 29);

(Rather than a function, getVal will probably have to be a procedure with 3
var parameters so you can return name and type as well as value.)

BTW, please don't use "this" as a variable, it confuses us old C++
programmers :-)
("this" in C++ means the same as "self" in Delphi.)

Also, I did try this out so I have a small working project that does it.

[Sid Gudes, cougar@roadrunner.com]

A:
If you're willing to pass the whole record at a time, then set your
function/procedure to expect an 'array of const' (keeps typechecking
safe, warm & fuzzy). This is identical to 'array of TVarRec'.

See Delphi online help for the system constants defined for TVarRec.

Function pointer

Question

Is The a similar concept to pointers to functions in delphi?
I have a toolbar with speed buttons which can be used by a number of diffrerent
forms in an app. Depending on which form is currently active I would like to
execute a different funtion if a button is pressed. I would hate to do this
using a huge case statement, Ideally what I wanted to do is register a function
with the toolbar button when a form gets focus and then simply call that
function when the speed button is pressed.

Answer

A:
This is what I came up with when building a simple states machine:

This is a very simple example of using function pointers under
Borland Delphi to control program flow.  Just create a simple form with
one button and add the code from Unit1 to the unit created.  Add Unit2
to the project and compile.  Give me a yell if you have any problems.

interface

uses
  SysUtils, WinTypes, WinProcs, Messages, Classes, Graphics, Controls,
  Forms, Dialogs, StdCtrls;

type
  TForm1 = class(TForm)
    Button1: TButton;
    procedure Button1Click(Sender: TObject);
  private
    { Private declarations }
  public
    { Public declarations }
  end;

var
  Form1: TForm1;
  CurrProc : LongInt;
  MyVal : LongInt;

implementation

uses Unit2;

{$R *.DFM}

procedure TForm1.Button1Click(Sender: TObject);
var
  NewProc : LongInt;
  MyString : string;
begin
  CurrProc := 2;                { beginning point in proc table }
  MyVal := 0;                   { dummy variable }
  NewProc := 0;                 { return value for next index in proc
table }
  while CurrProc < 6 do
    begin
    { execute the current index in the proc table and get the next proc
}
    NewProc := ProcTable[CurrProc](MyVal);

    { this is just to track the values of NewProc and CurrProc }
    FmtStr(MyString, 'NewProc [%d]  CurrProc [%d]', [NewProc,
CurrProc]);
    MessageDlg(MyString, mtInformation, [mbOK], 0);

    { set the current proc to the returned proc }
    CurrProc := NewProc;
    end;

end;

end.

{ This is a simple example of defining an array of function pointers }

interface

type
  { define Procs as a function }
  Procs = function(var ProcNum : LongInt): LongInt;

var
  { declare the array of function pointers }
  ProcTable : Array [1..5] of Procs;

{ function interface definitions }
function Proc1(var MyVal : LongInt) : LongInt; far;
function Proc2(var MyVal : LongInt) : LongInt; far;
function Proc3(var MyVal : LongInt) : LongInt; far;
function Proc4(var MyVal : LongInt) : LongInt; far;
function Proc5(var MyVal : LongInt) : LongInt; far;


implementation

uses Dialogs;

function Proc1(var MyVal : LongInt) : LongInt;
begin
  MessageDlg('Proc 1', mtInformation, [mbOK], 0);
  Proc1 := 6;
end;

function Proc2(var MyVal : LongInt) : LongInt;
begin
  MessageDlg('Proc 2', mtInformation, [mbOK], 0);
  Proc2 := 3;
end;

function Proc3(var MyVal : LongInt) : LongInt;
begin
  MessageDlg('Proc 3', mtInformation, [mbOK], 0);
  Proc3 := 4;
end;

function Proc4(var MyVal : LongInt) : LongInt;
begin
  MessageDlg('Proc 4', mtInformation, [mbOK], 0);
  Proc4 := 5;
end;

function Proc5(var MyVal : LongInt) : LongInt;
begin
  MessageDlg('Proc 5', mtInformation, [mbOK], 0);
  Proc5 := 1;
end;

initialization

  { initialize the contents of the array of function pointers }
  @ProcTable[1] := @Proc1;
  @ProcTable[2] := @Proc2;
  @ProcTable[3] := @Proc3;
  @ProcTable[4] := @Proc4;
  @ProcTable[5] := @Proc5;

end.

A:
     I think I would do something like this:
     Declare in each form procedures that handle the buttonpresses, like
     procedure CutButtonPressed(Sender:TObject) of Object;
     Then I would simply assign the buttons' OnClick events to these
     procedures in the forms OnActivate event. This would be the oop way to
     do it, but if you don't like it, I think Delphi still has function
     pointers.

A:
Define a base class form with an abstract function declaration for each
of the functions you want to call from your toolbar. Then derive each
of your forms from that base class form, and provide definitions for those
functions.
Eg: (There might be a couple of syntax errors here - I haven't compiled it)
type
  TBaseForm = class(TForm)
  public
    procedure Method1; virtual; abstract;
end;

type
  TDerivedForm1= class(TBaseForm)
  public
    procedure Method1; override;
  end;

  TDerivedForm2= class(TBaseForm)
  public
    procedure Method1; override;
  end;

  procedure TDerivedForm1.Method1;
  begin
    ....
  end;

  procedure TDerivedForm2.Method1;
  begin
    ....
  end;

{To call the function from your toolbar, get
the currently active form and call Method1}
procedure OnButtonClick;
var
  AForm: TBaseForm;
begin
  AForm := ActiveForm as TBaseForm;
  AForm.Method1;
end

Converting Real to a fraction of two integers

Question

I am using a rather slow function (see below) to convert a real
value to a fraction of two integers. Does anybody know of a better and
faster method as the one here presented?

Answer

A:
I have written a program that does just that. It's a dos program. You
call it with the decimal number passed as a parameter. It will print
3 columns, the first will be the continued fractions and the next two
will be the numerator and denominator. You will have to convert it
yourself to a function that you can call from your program, but that
should be to difficult.

To see how it works, I suggest that you try it as follows from the
DOS command line:

CONTFRAC 3.141592654

program contfrac;       { continued fractions }
{$N+}
const
        order   = 20;
var
        y,
        lasterr,
        error,
        x               : extended;

        a               : array[0..order] of longint;
        i,j,
        n               : integer;
        op,
        p,
        q               : longint;

begin
        lasterr := 1e30;
        val(paramstr(1), y, n);
        if n <> 0 then
                halt;
        x := y;
        a[0] := trunc(x);

        writeln;
        writeln(a[0]:20, a[0]:14, 1:14);

{ this is where the smarts are }

        for i := 1 to order do begin
                x := 1.0 / frac(x);
                a[i] := trunc(x);
                p := 1;
                q := a[i];
                for j := pred(i) downto 0 do begin
                        op := p;
                        p := q;
                        q := a[j] * q + op;
                        end;
                error := abs(y - int(q) / int(p));
                if abs(error) >= abs(lasterr) then
                        halt;
                writeln(a[i]:20, q:14, p:14, error:10);
                if error < 1e-18 then
                        halt;
                lasterr := error;
                end;
end.

A:
Here's an idea that I use that seems fast enough.  Here's the scheme:

We'll use the number 23.56.

Take your real number and do integer division by 1.

        23.56 div 1 = 23

Now subtract the result from the number you started with.

        23.56 - 23 = .56

To convert to int value just multiply by 100 if that is needed and recast.

             valA := (val div 100);
             valB := (valA - val); or valB := (valA - val) * 100;

                val = 23.56
                ValA = 23
                ValB = .56 or 56

Resizing (Dynamic) Arrays

Question

Coming from a background of higher level programming languages. I have
not had a lot of experience with array's in C++ or Pascal. I was
wondering if someone could clue me in on dynamic array's in delphi.

Answer

A:
There are several techniques for doing this.  The techniques depend on
whether you have an array of strings or an array of numbers (integer, real,
etc.).

1) If you just want a dynamic one-dimensional array of strings, I suggest
you look at the tStringList component, it takes care of all the management
overhead and is easy to use.

2) If you want a dynamic multi-dimensional array of strings, you can use
tStringList also (as long as the total number of elements is less than the
maximum for tStringList, I believe 16,000).  To do this, you write a
linearizing map function as follows:

Assume you have a three-dimensional array of strings, and the current
dimensions are [12,80,7], and you want to find element [n,m,x].  Then you
can resolve this to an element in a one-dimensional array by using
((n-1)*80*7 + (m-1)*80 + x).  You would then use this as an index into a
tStringList.  To dynamically alter one of the array bounds, use the move
method of tStringList to shuffle things around.  (This involves some
embedded loops but should be pretty quick to execute because tStringList
doesn't move the strings, only pointers to the strings.)

3) If you want a dynamic one-dimensional array of numbers, here's a general
technique, there are many other details.  Declare a pointer to an array type
that has the maximum number of elements for that type (remembering that
Delphi-16 only allows a type to occupy up to 64K), eg.
    type
       bigArray: array[1..32000] of integer;  {or ^double, etc.}
       pMyArray: ^bigArray;

then allocate the array using
   getMem (pMyArray, sizeof(integer) * n);

where n is the number of elements.  Then you can refer to an array element
using, eg.
   pMyArray^[51]

Don't forget to free the array after you're done with it using FreeMem.

To resize the array, define a new pointer, reallocate, and swap, eg.
   pTemp: ^bigArray;

   getMem (pTemp, sizeof(integer) * newnumelements);
   memcopy (pTemp, pMyArray, sizeof(integer)*n);
      {n is number of elements in pMyArray}
   freeMem (pMyArray, sizeof(integer)*n);
   pMyArray := pTemp;

4) To use a multi-dimensional array of numbers, combine the technique in (3)
above with the mapping function in (2) above.

5) If you need more than 64K in your array, you'll need to develop a
cascading list of pointers to chunks of memory, which is beyond what I can
explain here.

A:
I would encapsualte in an object. I use what I call my "Basic String
Object" (BSO), which does dynamic allocation and deallocation for 
strings of any size. Internally it is a PChar pointing to allocated
memory. Externally I have two properties: AsString and AsPChar. I have
various properties and methods allowing various methods of accessing
and manipulating the string.

I wrote my own malloc() calloc() and realloc() using a static private
TString object to track the allocated pieces.  This has worked wonderfully
for any time I need to grab a chunk of memory.

With the two I can allocate memory as needed (in chunks so as not to
waste too much CPU time), and is disposed of (when a certain amount of
slack exists -- again, so as to not waste too much CPU time).

Another idea that I like has already been presented (the open-ended
array). If you need bounds checking and/or dynamic resizing, you may 
be forced to use a method similar to what I've done with the string object
above, and use a default array property to allow for easy access. This 
allows you to use indices and types of any kind.

TMyDynamicObject =
...
 PROPERTY Array[ idx :LONGINT ]:TMyType READ GetArray WRITE PutArray DEFAULT;
...

VAR Mine :TMyDynamicObject;
...
Mine := TMyDynamicObject.Create;
FOR i := 10 TO 20 DO Mine[i] := {whatever}

{MONSTER MEMORY WASTER - unless you get really crazy and use hash tables }
Mine[-100000] := {whatever} 
Mine[+100000] := {whatever}

If you have a sparsely-populated array, using a hash table might
be profitable. I convert index values to strings and let TStrings do
the work when I'm really lazy and don't particularly care about the
overhead to build the conversion to strings.

A:
You can use TList (or TStringList.Objects) to store virtually whatever you
want!  TList.Items stores pointers to objects or records, but it doesn't do
anything with that pointer, so if you want you can typecast that to a longint, 
and not bother with the objects or records at all!  Here is an example of 
storing a list of integers in a TList:

var
  aList: TList;
  I : Integer;
  L : Longint;
begin
  aList := TList.Create;
  L := 93823;
  aList.Add(Pointer(L));
  aList.Add(Pointer(83293));
  for I := 1 to aList.Count do
    L := L + Longint(aList.Items[I-1]);
  aList.Free;
end;

You can have up to 16380 elements in a TList or TStringList.  Now here's an 
example of how to use a TList to store a record (or object):

type
  PMyRec = TMyRec;
  TMyRec = record
    Name: string[40];
    Addr : string[25];
    Comments: string;
    salary: Double;
  end;
var
  aList: TList;
  aRecPtr: PMyRec;
  I : Integer;
begin
  aList := TList.Create;
  New(aRecPtr);
  with aRecPtr^ do
  begin
    Name := 'Danno';
    Addr := 'unknown';
    Comments := 'What a guy!';
    Salary := 999000.00;
  end;
  aList.Add(aRecPtr);
  aList.Add(... );
  ...
  for I := 1 to aList.Count do
  begin
    aRecPtr := PMyRec(aList.Items[I-1]);
    {do something with the record}
  end;

{now dispose of all records, and the list object itself}
  for I := 1 to aList.Count do
    Dispose(PMyRec(aList.Items[I-1]));
  aList.Free;
end;

Use Free with records

Question

If I'm maintaining a TList full of pointers to records (NOT pointers to
objects), do I need to free the records it holds before freeing the TList
itself?  For example:

type
  PMyRecord: ^TMyRecord;
  TMyRecord = record
    MyString: string;
  end;

var
  MyRecord: PMyRecord;
  List: TList;
begin
  List := TList.Create;
  New(MyRecord);
  MyRecord^.MyString := 'Hi There';
  List.Add(MyRecord);
  MyList.Items[0].Free;  { <-- Do I Need This??? }
  List.Free;
end;

Answer

A:
You need to typecast the call to free with the right type, as follows:

var
     i    : integer;

begin
...
     for i := 0 to MyList.Count - 1 do
          dispose(PMyRecord(MyList[i]));
     MyList.Free;
end;

or

begin
     for i := 0 to MyList.Count - 1 do
          dispose(PMyRecord(MyList.items[i]));
     MyList.Free;

end;

Items is the default property, so you don't need to specify it, altough it's
ok if you do.

A:
Don't think of it as a function so much as a reserved word.  In the form:

        var
                p : ^mystruct;
        begin
                new(p);
                ...
                dispose(p);
        end;

the new() and dispose() operate exactly like the getmem() and freemem()
procedures except that the compiler supplies the number of bytes as the size
of the structure pointed to by the pointer variable.  The pointer must be a
typed pointer for this reason, so the following isn't valid:

        var
                p : pointer;
        begin
                new(p);
        end;

because there is no set size for the memory the pointer will point to.  On
the other hand, if you use getmem() and freemem(), you can allocate bytes to
an untyped pointer, as in:

        var
                p : pointer;
        begin
                getmem( p, 32767 );
                ...
                freemem( p, 32767 );
        end;

Create large arrays

Question

To be specific, I want to a 1 MEG array of bytes:
   BigArray : Array[0..999999] of Byte;
How can I do this in Delphi?

Answer

A:
In Delphi 16-bit, you can't do it directly.  In the new 32-bit, you _should_
be able to, but since it won't ship for a couple months I don't know yet.
(There are some beta testers out there who know, can they talk yet?)

In 16-bit Delphi, you need to work in chunks of 32K or 64K and map.  You can
do something like the following:

type
  chunk:     array[0..32767] of byte;
  pchunk:    ^chunk;
var
  BigArray:  array[0..31] of pChunk;

To create the array:

   for i := 0 to high(bigArray) do
      new (bigArray[i]);

To access the n'th byte within the array (n should be a longint):

   bigArray[n shr 15]^[n and $7FFF] := y;
   x := bigArray[n shr 15]^[n and $7fff];

   This will even do range checking if you have range checking set in your
options!
   n must be in the range [0..32*32*1024] = [0..1024*1024] = [0..1048576].

To free the array when you're all done:

   for i := 0 to high(bigArray) do
      dispose (bigArray[i]);

Pointer to a function

Question

I passed a pointer pointing to a procedure to my DLL.  How do I call
the procedure if all I have is the pointer.  I did use makeprocinstance to
get the pointer.

Answer

A:
This is what I normally use to call some functions from a DLL:

1. Declare a type:

type
  TYourDLLFunc = function(Parm1: TParm1; Parm2: TParm2): TParm3;

2. Declare a variable of that type:

var
  YourDllFunc: TYourDLLFunc;

3. Get the DLL handle:

  DLLHandle := LoadLibrary('YourDLL.DLL');

4. Get the address of the function:

  @YourDLLFunc := GetProcAddress(DLLHandle, 'YourDLLFuncName');

5. Use the YourDLLFunc variable as you would normally use the function, e.g.:

  Parm3 := YourDLLFunc(Parm1, Parm2);

Pass a function as a parameter

Question

Does anyone know how can I typecast a function's address into a
LongInt? Or is there a way to pass a function as a parameter?
Here is what I'm trying to do:

 function DllFunction(p: Pointer): Integer;
 far; external 'mydll';

 function foo: integer;
 begin
 result := 1;
 end;

 procedure test;
 var
 l: LongInt;
 begin
 l := Addr(foo);  { Compile Error!!! I tried @foo and }
                  { LongInt(foo), and they won't work neither. }
 { This is what I need. }
 DllFunction(foo);  { Compile Error!!! It can't take a function}
                    { as the parameter. }
 end;

Answer

A:
Sounds like what you need is a procedural type. Assuming that
DllFunction() wants functions that look like what you've described
above, something like the following should work: 

type
  TMyFuncType = function : integer ;

var
  MyFunc : TMyFuncType ;

function foo: integer;
begin
  result := 1;
end;

begin
  MyFunc := foo ;
  DllFunction( longint( MyFunc )) ;

You may also be able to get away with
  DllFunction( longint( @foo )) ;

though I'm not sure about all of the memory issues that may be involved 
with a .DLL calling a routine in another code segment like this, you may 
need to declare foo as far for this to work, or export it from the unit 
or something.

Also, depending on how DllFunction() is written, you might be able 
to declare it thusly, so that it does the typecast implicitly:

function DllFunction( p: TMyFuncType ): Integer; 
  far; external 'mydll';

so you wouldn't need the dummy MyFunc variable or the @ operator.

A:
You can pass functions as parameters in Delphi/Pascal. However you have to
set up a type for the compiler to use. Try the following (I actually
compiled and tested this):

unit Unit1;

interface

uses
  SysUtils, WinTypes, WinProcs, Messages, Classes, Graphics, Controls,
  Forms, Dialogs, StdCtrls;

type
  TForm1 = class(TForm)
    Button1: TButton;
    Button2: TButton;
    procedure Button1Click(Sender: TObject);
    procedure Button2Click(Sender: TObject);
  private
    { Private declarations }
  public
    { Public declarations }
  end;

var
  Form1: TForm1;

implementation

{$R *.DFM}

type
	IntFunc = function: integer;

function DllFunction(iFunc: IntFunc): integer; far;
begin
    DllFunction := iFunc; {Notice this is a function call}
end;

function iFoo: integer; far;
begin
	iFoo := 1;
end;

procedure TestIFunc;
var
	i: integer;
begin
	i := DllFunction(iFoo);
end;

procedure TForm1.Button1Click(Sender: TObject);
begin
	TestIFunc;
end;

procedure TForm1.Button2Click(Sender: TObject);
begin
	Close;
end;

end.

A:
Two things you can do.  First, if you want to use longint to pass it, you
can use
   i := longint(@foo).

The other thing you can do is bypass all this longint stuff and call the dll
function with
   DLLfunction (@foo);

Note that if you're planning to call foo from within the DLL, you're
probably going to need a thunk to resolve DS; look at MakeProcInstance for
more info.

Array of TPoints

Question

I need to set up an array of TPoints.  Let's say I have 5 points
and I know their X and Y values.  How do I fill and array with those values
for Tpoints?

Answer

A:
Const
  ptarr : Array[0..4] Of TPoint =
   ((x:0; y:4),
      .
      .
    (x:4; y:4));

Function return type

Question

Is there a way, using Object Pascal, to write a function which
is able to return more than one data type, i.e., returning a
byte or double or record ...
Actually I need some kind of polymorphic function...

Answer

A:
You can do that in C++. You can do it in ObjectPascal too, here's
the code snippet :

// function Chameleon returns different types by raising exceptions

unit Unit1;

interface

uses
  Windows, Messages, SysUtils, Classes, Graphics, Controls, Forms, Dialogs,
  StdCtrls;

type

  MyBoolean = class
  public
    Value : boolean;
  end;

  MyInteger = class
  public
    Value : integer;
  end;

  MyClass = class
  public
    Value : TStrings;
  end;

  TForm1 = class(TForm)
    Button1: TButton;
    procedure Button1Click(Sender: TObject);
  private
    { Private declarations }
  public
    { Public declarations }
    procedure MyProc;
    function Chameleon : boolean;
  end;

var
  Form1: TForm1;

implementation

{$R *.DFM}

function TForm1.Chameleon : boolean;
var
  b : MyBoolean;
  i : MyInteger;
  c : MyClass;
  r : integer;
begin
  r := Random(3);
  case r of
  0 :  begin
         b := MyBoolean.Create;
         raise b;
       end;
  1 : begin
        i := MyInteger.Create;
        raise i;
      end;  
  2 : begin
        c := MyClass.Create;
        raise c;
      end;
  end;    
end;

procedure TForm1.MyProc;
begin
  try
    Chameleon;
  except
    on MyBoolean  do ShowMessage('Function returned class MyBoolean');
    on MyInteger do ShowMessage('Function returned class MyInteger');
    on MyClass do ShowMessage('Function returned class MyClass');
  end;
end;

procedure TForm1.Button1Click(Sender: TObject);
begin
  Chameleon;
end;

end.

A:
Take a look at the Variant datatype in D2: this kind of code

function AnyType(const TypeParm: integer): Variant;
begin
  case TypeParm of
    1:  Result := 1;
    2:  Result := 2.0;
    3:  Result := 'Three';
    4:  Result := StrToDate('4/4/1944');
  end;
end;

is crappy programming - but quite legal!

A:
The following code snipped declares 3 procedures all same ingoing
parameters and all different output (as long as the output is physically
the same here it is 4 bytes). I don't think it is possible to fool delphi
to return a string that way. This would crash the heap manager.

Just as you need, call the appropriate function. Every call goes to
MyFuncRetAnything and P1 determines the return type. If you want you can
write another layer which makes the typecasting for you.

3 calls, 1 code.

I know this is not really what you need, but it is another approach.
(you can return strings as PChar which is also 4 bytes). But you must use
some memory allocated by the calling proc (maybe pass the result as P2?).

{my form has 3 labels and 1 button and this code}

var
  MyFuncRetInt : Function (P1, P2 : Integer) : Integer;
  MyFuncRetBool : Function (P1, P2 : Integer) : LongBool;
  MyFuncRetPointer : Function (P1, P2 : Integer) : Pointer;

function MyFuncRetAnything (P1, P2 : Integer) : Integer;
var
  RetPointer : Pointer;
  RetBool : LongBool;
  RetInteger : Integer;
begin
  RetPointer := nil;
  RetBool := False;
  RetInteger := 4711;
  case P1 of
    1 : Result := Integer (RetPointer);
    2 : Result := Integer (RetBool);
    3 : Result := RetInteger;
  end;
end;

procedure TForm1.Button1Click(Sender: TObject);
begin
  if MyFuncRetBool (2, 1900) then
    Label1.Caption := 'True'
  else
    Label1.Caption := 'False';
  Label2.Caption := IntToStr (MyFuncRetInt (3, 1900));
  Label3.Caption := IntToHex (Integer (MyFuncRetPointer (1, 1900)), 16);
end;

initialization
  MyFuncRetInt := @MyFuncRetAnything;
  MyFuncRetBool := @MyFuncRetAnything;
  MyFuncRetPointer := @MyFuncRetAnything;
end.









© DelphiRSS.com. All Rights Reserved.