Pascal Newsletter #36 - 02-JUN-2002
INDEX
1. A FEW WORDS FROM THE EDITOR
2. DELPHI'S SIGNATURE
3. USING ADO IN DELPHI 6
4. USING HTML HELP FILES IN YOUR PROGRAMS
5. INLINE ASSEMBLER IN DELPHI (I)
6. FORUMS
7. DELPHI ON THE NET
- Components, Libraries and Utilities
. Shareware/Commercial
. Freeware
- Articles, Tips and Tricks
- Tutorials
________________________________________________________________________
1. A FEW WORDS FROM THE EDITOR
In the Pascal Newsletter #34 we announced the release of a Portugese
version of this newsletter (the "Boletim Pascal"). Well, today I'm happy
to announce the release of the Russian Edition, edited by Mike Shkolnik:
* Pascal Newsletter - Russian Edition
http://groups.yahoo.com/group/pascal-newsletter-ru/
Subscription:
http://groups.yahoo.com/group/pascal-newsletter-ru/join
pascal-newsletter-ru-subscribe@yahoogroups.com
I'd like to thank the authors for the articles they contributed to this
issue and I'm glad to award S.S.B. Magesh Puvananthiran a license of
Greatis Print Suite, a set of components for print and preview, provided
by Greatis Software: http://www.greatis.com/delphicb/printsuite/
In the next issue, one of our collaborators will receive a license of
SMImport, a component suite to convert data from all popular formats,
provided by Scalabium: http://www.scalabium.com/smi/index.htm
We are running a competition for the first two Kylix articles we
publish. The prizes will be copies of AnyShape Transpack for Kylix by
MindBlast Software: http://www.mindblastsoftware.com/
As many of you probably know, Borland has made an important decision
about the future of the BDE. I guess all of us saw it coming... The BDE
SQL Links (for accessing data in database servers) will be shipped with
Borland products until the end of this year, but will be marked as
"deprecated" (no further enhancements or improvements will be made to
it). The BDE, without SQL Links, will continue to ship with Borland
products, but will be marked as "frozen" (meaning Borland will continue
to ship, test, and support existing BDE local table support but no new
enhancements will be made to the BDE, and no additional features or bug
fixes are planned). You can read more in this Borland Developer Network
article written by John Kaster:
http://community.borland.com/article/0,1410,28688,00.html
How does this decision impacts on your projects? Will you still use the
BDE for local databases, or do you plan to migrate them to Interbase
using IBX, or choose another solution? What about ADO? Is SQL Links
technology still a choice for new projects, or do you plan to migrate to
DataSnap Direct (aka dbExpress)? We'd like to hear your comments and
plans for the near future.
Ernesto De Spirito
eds2008 @ latiumsoftware.com
__________________
Collaborated in the edition of this issue: Dave Murray and José Manuel
Rodríguez. Articles by José Manuel Rodríguez, S.S.B. Magesh
Puvananthiran, Dave Murray and Ernesto De Spirito.
________________________________________________________________________
JfControls Library. Multi-language. Multi-appearance. Skins. Privileges.
More than 40 integrated and customizable components. Impressive GUI.
Centralized resources administration. Multiple programming problems
solved. For Delphi 3-2006 & C++ Builder 3-6. http://www.jfactivesoft.com
________________________________________________________________________
2. DELPHI'S SIGNATURE
By José Manuel Rodriguez (JMR) <jmr@clubdelphi.com>
Intro
=====
Not long ago, I saw in one of Latium Software's forums a question about
how could one tell whether a certain program was compiled with Delphi.
Though there were some answers recommending the use of commercial or
shareware applications, such as the famous PE Explorer, there was no
direct answer to this question. The fact is that there is a way, and it
is quite straightforward too: since the times of Delphi 3 onwards, every
file, of any kind: GUI executable, Console Application or DLL (including
ActiveX Controls but not Packages) has an embedded "Delphi's signature".
Windows Resources
=================
Most Windows applications contain what are called Resources. Resources
were introduced in an early stage of Windows's life due to its visual
graphic nature: even though it's perfectly possible to generate the
graphic elements needed by an application by pure code (and certainly
that's the only way programs such as Resource Editors must deal with
them), that's quite awkward and cumbersome. Instead, you design these
graphical elements visually with the aid of special programs called
Resource Editors (for example, we draw a dialog box in a graphical
environment) and then we set down in the appropriate places elements
such as buttons, edit windows, etc. Once we think it looks is OK, we
save it as a binary resource and now it is ready to be embedded into our
EXE. Here, and from now on, by EXE we mean any file that is in the PE
(Portable Executable) Format supported by Win32, like EXEs, DLLs, OCXs,
etc.
Given the fact that some of these types of binary data are used again
and again in nearly every application, a series of these binary
resources were defined as standard resources:
Accelerator table
Bitmap
Cursor
Dialog box
Enhanced metafile
Font
Icon
Menu
Message-table entry
String-table entry
Version information
Besides these Standard Resources, there is another type of resources:
Custom Resources or User Defined Resources. These Resources are defined
as needed by the programmer and they consist sometimes of binary data
that only makes sense to the programmer or the application, sometimes of
well-known formats but which are not part of the standard, for example,
JPEG or WAV files.
Back to Delphi, one could think that every Form we create in the Delphi
IDE would be rendered as the Standard Resource known as "Dialog Box",
but it is not so. Instead, due to the "two way technology of the IDE",
its way of working with components and storing RTTI, etc, the creators
of Delphi decided to store each Form, along with all the components
owned by it, as a Custom Resource. But there is more to it, besides
including bitmaps, icons, etc and obviously all the Custom Resources
derived from the Forms, since version 3.0 Delphi also includes two extra
Custom Resources: one containing information about the packages used and
another which is really the signature of the programming environment.
The later is a Borland specific resource called DVCLAL (Delphi Visual
Component Library Access License), and is included automatically by the
Linker -with no intervention of the programmer- in every program made
with Delphi. In my opinion this term is confusing as Console Apps that
don't use the VCL at all have this resource embedded in them too.
Resources inside a Program
==========================
As we have said before, resources are binary data. In fact, it's
precisely these pieces of binary data that are considered to be
resources (.RES), and can be generated directly with a Resource Editor,
but there are resources in plain ASCII Files too (.RC mainly, but also
.DLG, etc.). These "resource source files" need to be compiled with a
Resource Compiler (BRCC32) to generate the final .RES mentioned above.
The fact is that, once embedded within a PE Files, resources suffer no
further modification. This means that we can open any PE File and have
a look directly at its resources. If you want to, you can open a PE and
with the help of a Resource Editor, translate all of its strings into
the language you desire, without needing to have the source code or
having to recompile. Windows API has a wealth of functions that allow
access to and handle these resources with little effort (some of these
routines only do work in NT) and as we will see the Delphi RTL and VCL
include functions that are even easier to work with. In our case, to
determine whether program has been created with Delphi we have to check
for the existence in the PE of a resource called DVCLAL, and if it
exists, we can check that resource is indeed a proper "Delphi signature"
and it's not a mere coincidence. That being the case we can be assured
that the PE has been compiled by Delphi.
The reason for these kind of resources and their differences, not
only among the various version of Delphi, but even between the
Professional and C/S (or Enterprise) releases of the same version of
Delphi isn't quite clear to me. Apparently, Borland makes use of these
resources, along with a set of variables and routines defined in the
Unit SysUtils, not just to be able to determine whether a program has
been created with Delphi but to avoid making a fraudulent use of the
License terms and forbid, for example, buying the Professional version
of Delphi 5 and getting the RTL/VCL libraries for Delphi 5 Enterprise,
using them with the Professional version to create programs that
otherwise would be only feasible by aquiring the Enterprise version. In
Delphi, there are two array variables defined in the Unit SysUtils: AL1s
and AL2s. And a set of procedures and functions are also defined: AL1
and AL2 (they seem to be used in the job of encrypting/decrypting), GDAL
and ALR (Get Delphi Access License and Access License Resource) and the
auxiliary functions RCS and RPS (probably Resources Client/Server and
Resource Professional). These functions are called from certain places
each time a Delphi module (DLLs and Packages included) is loaded into
memory. In case you are not using the proper library with the
corresponding IDE, which implies you have no License Rights, the
procedure ALV (Access Licence Violation?) is invoked, which will prevent
the program from executing. Thus, for instance, GDAL is called by
DBTABLES.PAS (which makes it impossible to use the DBE without License
Access) or by SCKTCOMP.PAS (which means that trying to make a program
TCP/IP enabled with the wrong Delphi libraries will not be allowed).
Let's get to work!
==================
First at all, we've got to open the file. In order to do so, we are
going to use the API call LoadLibraryEx. Why do we use this function
instead of the more familiar LoadLibrary? Well, the function LoadLibrary
is used primarily to load DLLs into the calling process address, and for
this reason, in addition to just loading it, it has to handle the
mapping of the DDL in the process address, finding and resolving the
entry points and the like. Here, as we are only interested in opening
the PE file to read it, there is no need to do those additional tasks
so calling LoadLibraryEx with the parameter LOAD_AS_DATAFILE helps us
prevent those extra jobs and is noticably quicker and simpler:
hModule := LoadLibraryEx(PChar(cModuleName), 0,
LOAD_LIBRARY_AS_DATAFILE);
hModule being a variable of type THandle.
Once we've got the PE file loaded in memory and a handle to reference
it, the next step is to examine all the resources till we find the
Custom Resources. There are identifiers defined in Windows for all types
of resources, for example: RT_BITMAP, RT_STRING, RT_DIALOG, etc. Custom
Resource Types are identified globally by RT_RCDATA. To examine those
different kinds of resources the Windows API offers the function
EnumResourceTypes. This function is an enumeration function whose way
of working may sound a little odd for the common Delphi programer. The
syntax of the function is:
function EnumResourceTypes(hModule: HMODULE; lpEnumFunc: Pointer;
lParam: Longint): BOOL; stdcall;
The expected parameters are the handle we have got from the call to
LoadLibraryEx and a pointer to a callback function. The third parameter
is any 32 bit value that we might opt to use for our own purposes (or
ignore it). The question that arises is, what does this really mean by a
callback function? To put it short, it's just a function that instead of
being called directly by us, that is, by our code, we pass it over to
Windows and Windows itself will call it for us when appropriate. In the
case of the callback of an enumeration function, that means that the
enumeration function will call the callback function for each element of
the enumeration. Take care that, being the callback function called by
the OS, i.e., Windows and not by our code, it must follow the calling
convection of Windows, not Pascal's, thus you must make sure that the
function is declared as stdcall. Another question that may arise is:
what is really the meaning of the second parameter, lpEnumFunc? Could it
be any pointer? Well, definitively no, it can't be any type of pointer,
it must be a pointer to a function of the type:
function EnumResTypeProc(hModule: THandle; szType: PChar;
lParam: LongInt): Boolean; stdcall;
For each type of resource EnumResourceTypes finds, it will call
EnumResTypeProc passing to it the Handle of the Module, the type of the
resource it has found and the optional parameter. EnumResourceTypes will
keep on enumerating the different resources it finds as long as there
are still types of resources left to be enumerated and as long the
function returns true, so in our case, we must force our function to
return False as soon as the type RT_RCDATA is detected. It's very
important that the second parameter mentioned earlier be a pointer to
the right type of function. If we look for EnumResourceTypes in Windows
SDK, what we really get is:
function EnumResourceTypes(hModule: HMODULE;
lpEnumFunc: ENUMRESTYPEFUNC;
lParam: Longint): BOOL; stdcall;
but the type ENUMRESTYPEFUNC is nothing but another name for the type
TFarProc, which in turn is another name for a Pointer. As defined, the
function is waiting for a pointer and this way any pointer you hand
over to it will be accepted at compile-time so you must be extremely
careful with what type of pointer you pass. Should it be a pointer to
anything else than a pointer to the proper type of function no error
will be flagged at compile-time, but, at run-time, consequences may be
anything but agreeable, and most probably disastrous. In our beloved
Object Pascal, we'd have defined instead the type TEnumResTypeFunc as:
function(hModule: THandle; szType: PChar; lParam: LongInt): Boolean;
And, any function that would have required a variable of type
TEnumResTypeProc as a parameter and were passed another type would flag
a clean error at run-time, thus preventing harder to debug and
potentially far more dangerous runtime errors. The problem here is that
EnumResourceTypes is a Windows API function and as such is written in
the C language. The only way for C to support the passing of functions
as parameters to another function is through the use of pointers to
functions that allow no compile-time checking, contrary to Pascal which
in addition to pointers to functions supports the robust functional or
procedural types.
So our callback function in a first approximation will be something
like:
function EnumTypes(hModule: THandle; szType: PChar;
lParam: LongInt): Bool; stdcall;
begin
if szType = RT_RCDATA then
...
Result := False;
else
Result := True;
end (*EnumTypes*);
As we can see, if the type of resource found isn't the expected one
(RT_RCDATA) we return True so that the enumeration continues, and if it
is the correct type of resource, we process it (we'll fill in the
ellipsis later) and we return False in order to stop the enumeration.
The call would be:
hModule := LoadLibraryEx(PChar(cModuleName), 0,
LOAD_LIBRARY_AS_DATAFILE);
if hModule <> 0 then
EnumResourceTypes(hModule, @EnumTypes, 0)
Notice the use of the @ operator to pass the address of (that is, a
pointer to) the callback function EnumTypes.
So we have now nearly finished the skeleton of our program: open the
candidate file and find out whether it has Custom Resources. If it does,
then find out whether there's one whose name is DVCLAL. To do this,
Windows offers an enumeration function very similar to the one we have
just seen, but this time, the function enumerates all the names of the
resources of a given type. The syntax of this new function is:
function EnumResourceNames(hModule: HMODULE; lpType: PChar;
lpEnumFunc: Pointer;
lParam: Longint): BOOL; stdcall;
And this time, the awaited callback function is prototyped as:
function EnumResNamesProc(hModule: THandle; szType: PChar;
szName: PChar; lParam: LongInt): Bool;
stdcall;
Its way of working is quite similar to what we have just seen. Thus, for
each type of resource we pass to it, the function will call the callback
with each of the names of the resources of that type till all names of
that type have been enumerated or till we return False. Since it works
exactly the same as we've just seen for EnumResourceTypes, we are not
going to detail more in this function.
So, our main program would look rather like:
function EnumNames(hModule: THandle; szType: PChar;
szName: PChar; lParam: LongInt): Bool; stdcall;
begin
if szName = 'DVCLAL' then
begin
Boolean(Pointer(lParam)^) := True;
Result := False;
exit;
end (*if*);
Result := True;
end (*EnumNames*);
function EnumTypes(hModule: THandle; szType: PChar;
lParam: LongInt): Bool; stdcall;
begin
if szType = RT_RCDATA then
Result := EnumResourceNames(hModule, szType, @EnumNames, lParam)
else
Result := True;
end (*EnumTypes*);
function IsDelphiModule(const cModuleName: String): Boolean;
var
hModule: THandle;
begin
Result := False;
hModule := LoadLibraryEx(PChar(cModuleName), 0, LOAD_AS_DATAFILE);
if GetLastError = 0 then
EnumResourceTypes(hModule, @EnumTypes, LongInt(@Result))
else
RaiseLastWin32Error;
end (*IsDelphiModule*);
As you can see, it consists mainly of a two-level nest of functions. For
each candidate PE file, the first thing we do is to call LoadLibraryEx
to obtain a handle. Next, we call EnumResourceTypes with that Handle
and these functions in turn calls EnumType with whatever type of
resource it finds. If the type is precisely RT_RCDATA, then EnumTypes in
turn calls EnumResourceNames which in turn call EnumNames with the names
of the resources of type RT_RCDATA it has found. If the name of the
resource passed to EnumNames is DVCLAL we assume that our seek is done
and that the file is created by Delphi so we stop the enumeration.
Really, we ought to read the RAW DATA contained in the resource and make
sure that is really a Delphi signature and not a coincidence. To do that
we would need to know how to access a determinate resource and also the
exact structure and meaning of a Delphi signature. Accessing a
determinate resource will not be covered in this article but in a future
one, and as for the structure of DVCLAL, I must admit I haven't guessed
it yet, though a little discussion follows bellow.
Here we have employed a trick (I'd call it a smart technique, but that
might be because I have no grandmas to praise me). If you remember,
there was an optional 32 bits wide parameter, well, given the fact that
EnumResourceTypes is being called from a function that returns a
Boolean, what we pass in this parameter is a pointer to this value, what
would be equivalent to passing it by reference (in the C language all
parameters are passed by value, so to simulate a parameter being passed
by reference you have to resort to passing a pointer to it). This way
as this parameter is "dragged" all along the nesting, we have a
reference to the value that is going to be returned by the main
function so we can set its value at will and we do so when we find a
resource type of RT_RCDATA whose name is DVCLVAL.
As far as the binary structure of a DVCLAL is concerned, I have little
to say about it. I have determined empirically some values for the C/S
or Enterprise releases of some versions of Delphi but I haven't had
enough spare time to decypher it nor have I found anywhere where I could
get this information from. These are the values I've found:
For Delphi 3.xx Client/Server
DVCLAL RCDATA
{
'A2 8C DF 98 7B 3C 3A 79 26 71 3F 09 0F 2A 25 17'
}
For Delphi 4.xx, 5.xx & 6.xx Enterprise:
DVCLAL RCDATA
{
'26 3D 4F 38 C2 82 37 B8 F3 24 42 03 17 9B 3A 83'
}
An additional problem I haven't mentioned is that at least Borland C++
Builder 4.xx and 5.xx seem to have the same signatures as their Delphi
counterparts, so it's possible to identify wrongly a PE file created
with C++ Builder as being created by Delphi or vice versa. Maybe the
information contained in the RT_RCDATA Resource called Package Info
gives additional information that can help us to solve the mess, but at
the time of writing this I haven't been able to solve it either.
And ... what's next?
====================
By now we have got conversant with Windows Resources and learnt how to
examine any PE file and know the resources it has. To tell the truth, if
all we needed was to test for the existence of a well known resource and
access to its content, we could have skipped the enumerations and have
gone directly to it. The Windows API (with FindResource and
LoadResource) and above all, the VCL (with its class TResourceStream)
can both make this task incredibly easy. However, this way we are
prepared not only to check for the "Delphi signature" but to access all
of the resources of a given PE file. In a future article, we'll learn
how to examine all the resources of a PE File, and if it is Delphi made,
even how to access the forms and show them, even though they are Custom
Resources and Standard.
José Manuel Rodriguez (JMR)
__________________
NOTE: Any suggestions, corrections or constructive criticism would be
welcome at the author's e-mail address: jmr@clubdelphi.com.
All the code mentioned in this article is original by the author and is
available as a demo app in the zip file bundled with this e-zine.
________________________________________________________________________
3. USING ADO IN DELPHI 6
By S.S.B. Magesh Puvananthiran <sesbaNOSPAM@hotmail.com>
This article is intended to demonstrate how can we use the ADO
components available in Delphi.
I have written a simple application using ADO components to retrieve the
Data Source Names, table names, field names, procedure names and an
option to write a query, execute it and display the result in a grid.
The function of the application:
When you run the application, it'll fetch all the ODBC Data Source Names
from the current system and show them in a list box. If you select a
Data Source Name, you will be asked to enter the user name and password.
Once you enter the right user name and password, the tables and
procedures available in the data source will be listed. And if you click
on a table name, all the fields in the table will be listed.
In the memo field you can enter an SQL query and click on the Execute
button to execute the query and display the result in the grid below.
Also you can save the query to a text file if you click on the Save
button.
If you right click the Data Source Names list box, you'll find a
Refresh menu item to refresh the ODBC Data Source Names.
The complete code for the application is attached. This is really a
simple version of a Query Builder and we can add as many features as we
want, and I just wanted to share it with you. Even though there are so
many query builders available, I wanted to try writing one with Delphi's
ADO components and I am going to expand this by adding more features. I
welcome your ideas and suggestions for this.
Thanks.
Magesh.
________________________________________________________________________
4. USING HTML HELP FILES IN YOUR PROGRAMS
By Dave Murray <irongut @ vodafone.net>
Do you long to move from WinHelp to HTML Help in your programs? The unit
attached (dmHTMLHelp.pas) converts WinHelp calls to HTML Help enabling
you to upgrade with the minimum of effort. This article is based on an
article I wrote for Delphi3000.com:
http://www.delphi3000.com/articles/article_2994.asp
Save this unit in a directory on your Library path (Tools|Environment
Options|Library|Library Path) and add it to your project uses clause.
WinHelp requests will now be translated to HTML Help calls so you can
use your help file just as you previously did.
Specify your *.chm file in the Project Options|Application|Help file
setting. Context sensitive help will work as it previously did. You can
also use TApplication.HelpCommand to send help commands. Eg.
Application.HelpCommand(HELP_KEY, DWORD(keyData));
NOTE:
* This unit assigns its own handler to the Application.OnHelp event.
DO NOT assign your own handler to Application.OnHelp.
* This unit ignores any form's HelpFile property. (Delphi 4+)
________________________________________________________________________
5. INLINE ASSEMBLER IN DELPHI (I)
By Ernesto De Spirito <eds2008 @ latiumsoftware.com>
This article simply intends to introduce you to the world of inline
assembler in Delphi. It will barely give you an idea, and it doesn't
intend to explain all the details of assembler programming, that will
probably require an entire book...
Why and when
============
If you take a look at the source code of the RTL and the VCL, you'll see
inline assembler statements in various places. Why would Borland code
parts of the RTL and the VCL in assembler? The answer is quite simple:
to achieve execution speed. We know the compiler produces fast code, but
a compiler can never be better than a professional assembler programmer.
Now, if assembler is so good, why isn't the entire RTL and VCL coded in
assembler? The answer is also simple: because a higher level programming
language is easier to code, debug, read, and maintain, making it worth
to sacrifice some speed for this convenience. This would help explain
when assembler code should be used. To put it bluntly, apart from
low-level system access, inline assembler is used when the difference in
speed justifies the bother of coding in assembler. For example, in the
unit Math.pas there is a lot of assembler, mainly for low-level system
access (specifically, to access coprocessor features), and you'll see
many assembler blocks, this time for speed, in system.pas, sysutils.pas,
and classes.pas, which isn't strange since they can be considered the
core units of the RTL and the VCL.
In general, procedures and functions that are very likely to be called
quite often in a program, should be highly optimized, but coding in
assembler should be avoided to the maximum extent possible. If we want
speed, before considering coding in assembler we should first improve
the algorithm, and then optimize our Pascal code. If we decide to go for
assembler, the optimized Pascal code would be useful for documentation
purposes, and it might act as some sort of "backup code" in case in the
future we have problems in maintaining the assembler source code.
The CPU registers
=================
CPU registers are like predefined variables, but they reside in the CPU,
and sometimes they have special purposes. They don't have a type, but
you can consider them as signed or unsigned 32-bit integers, or as
pointers, depending on the case.
Since registers are located in the CPU, it is faster to access values
stored in the registers than values stored in memory, so registers are
used very much to cache values.
Like variables, registers have names. The names of the registers we
will use most are EAX, EBX, ECX, EDX, ESI, EDI, EBP and ESP. Each
register has its own particularities:
- For some instructions, the CPU is optimized for using the EAX
register (also known as "accumulator"), or at least the opcodes
are smaller. EAX is used in multiplications and divisions (low
order 32 bits of the operand and the result), string instructions,
port I/O instructions, ASCII adjust and decimal adjust instructions,
and in some special instructions (like CDQ, LAHF, SAHF, XLAT).
- EBX is a general-purpose register, and is implicitly used by XLAT.
- ECX (also known as "counter") has a special use with the LOOP
instruction, bit rotating and shifting instructions, and string
instructions.
- EDX is used in multiplications and divisions (high order 32 bits of
the result of a multiplication, or high order 32 bits of both the
dividend and remainder of a division) and in some other special
instructions (like CDQ).
- ESI and EDI (known as the "source index" and "destination index"
respectively) are like pointers used by string instructions to
identify the source and destination of data, respectively.
- EBP (known as the "base pointer") is usually used for addressing
values in the stack (parameters and local variables).
- ESP (known as the "stack pointer") is used to control the stack. It
is modified automatically by instructions like PUSH, POP, CALL and
RET, but can be modified by code and it can even be used as a general
purpose register (as long as we preserve it).
The registers EBX, ESI, EDI, EBP, and ESP should be preserved in inline
assembler blocks, meaning that before using these registers we should
save their values somewhere (usually the stack or another register), and
when we are finished we should restore their original values. Since this
saving and restoring implies instructions and therefore time, we'll only
use these registers when the difference justifies it or when they are
inevitably needed.
Probably you noticed all register names start with the letter "E". It
stands for "Extended". In the old Intel 80286, registers had 16 bits and
had names like AX, BX, CX, etc. These registers still exist, and they
are the least significant 16-bits (the "low words" or "low order words")
of EAX, EBX, ECX, etc., respectively. By the way, the registers AX, BX,
CX and DX are divided into two 8-bit registers. AL, BL, CL and DL are
the low order bytes of AX, BX, CX and DX respectively, while AH, BH, CH
and DH are the high order bytes of AX, BX, CX and DX respectively. For
example, if the value of EAX is $7AFD503C, then the value of AX is
$503C, the value of AH is $50 and the value of AL is $3C:
7A FD 50 3C
AH AL
/----/
AX
/------------/
EAX
If for example we store $99 in AH, then the value of EAX would be
$7AFD993C.
There is a special register, the Flags Register, which holds binary
flags set by the mathematical and logical instructions, or explicitly
by code, and they are used by conditional jump instructions. The Carry
Flag is also used in some bit rotating instructions, and the Direction
Flag is used in string instructions. This register isn't addressable by
name like the other registers, but it can be saved and restored from the
stack using the PUSHF and POPF instructions respectively, and it can
also be partially get in the AH register using the LAHF instruction, and
restored from AH using the SAHF instruction.
Assembler instructions
======================
Assembler instructions are enclosed in asm..end blocks, and have the
form
[label:] [prexix] opcode [operand1 [, operand2 [, ...]]]
The opcode is the name of the instruction, like MOV, ADD, PUSH, etc.
Instructions can be separated by semicolons, line breaks or comments. By
the way, comments should be in Object Pascal style, i.e. the semicolon
is not the start of a comment till the end of line as it is in ordinary
assembler.
The following, is an example of an asm..end block mixing different kinds
of comments and instruction separations:
asm
xchg ebx, edx; add eax, [ebx]; {semicolons separate statements}
// line breaks separate statements
mov ebx, p
sub eax, [ebx] (*comments separate statements*) mov ebx, edx
end;
The convention is to use line breaks for separation, like this:
asm
xchg ebx, edx
add eax, [ebx]
mov ebx, p
sub eax, [ebx]
mov ebx, edx
end;
In the source code of the VCL you'll see that opcodes and register names
are written in capital letters, and instructions are indented eight
characters, but we won't use this convention here.
Asm..end blocks can occur anywhere in the source code where a Pascal
sentence can occur, and we can write 100% assembler procedures and
functions if use "asm" instead of "begin", like this:
procedure test;
asm
// assembler statements
end;
Notice that these two implementations are not the same:
function f(parameters): type;
begin
asm
// assembler statements
end;
end;
function f(parameters): type;
asm
// assembler statements
end;
The reason is that the compiler performs certain optimizations when we
implement procedures and functions completely in assembler (without
using the begin..end block).
Labels should be declared with a Label section, as in any other Object
Pascal code, unless they are prefixed by "@@":
function IsMagicNumber(x: integer): boolean;
asm
cmp eax, MagicNumber
je @@Bingo
xor eax, eax
ret
@@Bingo:
mov eax, 1
end;
Labels prefixed by "@@" are local to the inline assembler block in which
they are used. This will generate a compiler error:
begin
....
asm
....
@@destination:
....
end;
....
asm
....
jnz @@destination // Error
....
end;
....
end;
To correct it, we need to use a conventional label, local to the
procedure or function:
label
destination;
begin
....
asm
....
destination:
....
end;
....
asm
....
jnz destination // Right
....
end;
....
end;
Operands
========
Sometimes an operand or operands are implicit. For example, the
instruction CDQ (Convert Dword to Qword) apparently takes no operands,
but it works with EDX and EAX (it extends the most significant bit of
EAX, the "sign" bit, into EDX, so EDX:EAX will represent the integer
in EAX converted to Int64, where EAX will hold the 32 least significant
bits, and EDX will hold the 32 most significant bits).
For most instructions, operands can be registers. For example
mov eax, ecx
copies the value of ECX in EAX.
Many operands can be immediate values. For example:
mov eax, 5
mov eax, 2 + 3 // Constant expression, resolved at compile time
mov al, 'A' // The ASCII code of 'A' is $41 (65)
mov eax, 'ABC' // Equivalent to MOV EAX, $00414243
Many operands can be memory references. For example:
mov [ebx], eax // EBX^ := EAX;
Memory references can have many forms:
mov eax, [$000FFFC] // Absolute address
mov eax, [ebx] // Register
mov eax, [ebp-12] // Register plus/minus constant offset
mov eax, [ebp+ebx] // Register plus offset in a register
mov eax, [ebp+ebx+8] // Register plus offset in a register
// plus/minus constant offset
mov eax, [ebp+ebx*4] // Register plus offset in a register
// multiplied by a constant
mov eax, [ebp+ebx*4+8] // Register plus offset in a register
// multiplied by a constant,
// plus/minus constant offset
The use of Pascal identifiers is translated to one of the forms above:
mov eax, parameter // mov eax, [ebp + constant_offset]
mov eax, localvar // mov eax, [ebp - constant_offset]
mov eax, globalvar // mov eax, [absolute_address]
call procname // call absolute_address
First example
=============
We are ready to learn some opcodes with a couple of examples. We can
begin with a simple function:
function f(x: integer; y: integer): integer;
// f(x,y) = (-x-y+5)*7
{
begin
Result := (-x - y + 5) * 7;
end;
}
asm
// Parameters are passed in EAX (x) and EDX (y);
neg eax // EAX := -EAX; // EAX = -x
sub eax, edx // EAX := EAX - EDX; // EAX = -x-y
add eax, 5 // EAX := EAX + 5; // EAX = -x-y+5
imul 7 // EAX := EAX * 7; // EAX = (-x-y+5)*7
end;
The first three parameters (left to right) are passed in EAX, EDX and
ECX. For methods, the first parameter is Self (passed in EAX), and the
first parameter explicitly declared is in fact the second parameter
(passed in EDX), and the second explicit parameter is actually the
third parameter (passed in ECX).
The return value should be placed in EAX for 32-bit ordinal values
(AX and AL should be used to return 16-bit and 8-bit ordinal values
respectively).
The comments explain the opcodes quite well, but for IMUL we have to add
two things:
* IMUL considers the operands (EAX and 7 in the example) as signed
integers (we should use MUL when the operands are unsigned)
* The result of the multiplication is a 64-bit integer (the most
significant 32 bits of the result are placed in EDX).
Multiplications are quite expensive in terms of CPU time, and sometimes
it is faster to substitute them with bit shifting (when we multiply or
divide by a power of two), additions and subtractions. For example:
a * 7 = a * (8 - 1)
= a * 8 - a
= a * 2^3 - a
a * 7 = a shl 3 - a
Instead if IMUL 7, we can do the following:
mov ecx, eax // ECX := EAX; // ECX = -x-y+5
shl eax, 3 // EAX := EAX shl 3; // EAX = (-x-y+5)*8
sub eax, ecx // EAX := EAX - ECX; // EAX = (-x-y+5)*8 - (-x-y+5)
// EAX = (-x-y+5)*7
Let's see another example:
function remainder(x: integer; y: integer): integer;
// Returns the remainder of x divided by y
{
begin
Result := x mod y;
end;
}
asm
// Parameters are passed in EAX (x) and EDX (y);
mov ecx, edx // ECX := EDX; // EDX = y
cdq // EDX:EAX := Int64(EAX); // EAX = x
idiv ecx // 32-bit signed integer division:
// EAX := Int64(EDX:EAX) div integer(ECX);
// EDX := Int64(EDX:EAX) mod integer(ECX);
mov eax, edx // Result := EDX; // remainder
end;
The stack
=========
When a program is loaded, it gets assigned a stack, which is a memory
region used as a LIFO (Last In, First Out) structure, controlled by the
ESP register, which points to the stack top. ESP starts pointing to the
end of the region, so every time we push a 32-bit value, the ESP
register gets subtracted 4 (bytes), and the value is stored in the
location pointed by ESP.
| |
+-----------+
| |
+-----------+
| $01234567 | <- ESP
+-----------+
| |
PUSH $89ABCDEF // SUB ESP,4; MOV [ESP],$89ABCDEF
| |
+-----------+
| $89ABCDEF | <- ESP
+-----------+
| $01234567 |
+-----------+
| |
Conversely, when we pop a 32-bit value, the value is retrieved from the
location pointed by ESP, and ESP is added 4 (bytes).
POP EAX // MOV EAX,[ESP]; ADD ESP,4
| |
+-----------+ +-----------+
| $89ABCDEF | EAX | $89ABCDEF |
+-----------+ +-----------+
| $01234567 | <- ESP
+-----------+
| |
The stack is used to store the return address of procedures and
functions, parameters, local variables and intermediate results.
In the following example we use the stack to save the value of a
register for later use:
function IntDiv(x: integer; y: integer; r: pinteger = NIL): integer;
// Returns the integer quotient of x / y, and the remainder in r
{
begin
Result := x div y;
if r <> NIL then r^ := x mod y;
end;
}
asm
// Parameters are passed in EAX (x), EDX (y) and ECX (r)
push ecx // Save ECX (r) for later use
mov ecx, edx // ECX := EDX; // ECX = y
cdq // EDX:EAX := Int64(EAX); // EAX = x
idiv ecx // 32-bit signed integer division:
// EAX := Int64(EDX:EAX) div integer(ECX);
// EDX := Int64(EDX:EAX) mod integer(ECX);
pop ecx // Restores ECX (ECX := r)
cmp ecx, 0 // if ECX = NIL then
jz @@end // goto @@end;
mov [ecx], edx // ECX^ := EDX; // remainder
@@end: // local label (preceded by "@@")
end;
Notice that for every PUSH we make we have to perform a POP, so the
value of ESP is left unchanged (ESP is one of the registers we have to
preserve).
The CMP instruction subtract the second operand from the first (ECX-0
in this case), like the SUB instruction, but the result is not stored
anywhere, although the Zero flag will be set (turned on) or cleared
(turned off) depending on whether the result is zero or not, as it
happens with all mathematical and logical instructions (except in
certain cases). We can take advantage of this fact, and instead of
writing
cmp ecx, 0
we can write
or ecx, ecx // ECX := ECX or ECX;
The result of ECX Or ECX is ECX itself, so the value stored in ECX is
the same it had before the operation, but -like we said above- the Zero
flag will be set if the result is zero (i.e., if ECX was zero). We use
OR instead of CMP because OR operates on two registers, just taking 2
bytes to code, while CMP operates a register with an immediate 8-bit
value, taking three bytes to code, but CMP doesn't actually write to
the destination (ECX in this case) like OR does, which is sometimes
important when writing code optimized for Pentium. TEST ECX, ECX is
usually preferred because it combines the best of both worlds (two bytes
to code and doesn't write to the register: just performs a bitwise AND
operation to set the flags based on the result, which is discarded).
JZ (Jump if Zero), goes (jumps) to the label indicated as operand if the
Zero flag is set (on), or continues with the normal execution flow it
the Zero flag is cleared (off).
Passing parameters on the stack
-------------------------------
Let's go back to the stack. We said the first three parameters of a
function were passed on EAX, EDX and ECX, but what if we have or more
parameters? Additional parameters are passed on the stack, left to
right, so the last parameter, will be the first on the stack.
Let's suppose we have a function
function Sum(a, b, c, d, e: integer): integer;
begin
Result := a + b + c + d + e;
end;
and that we want to make the call
Sum(1,2,3,4,5);
In assembler, it would be like this:
mov eax, 1
mov edx, 2
mov ecx, 3
push 4
push 5
call Sum
The CALL instruction pushes the return address on the stack and jumps to
(starts executing) the function. The RET (RETurn) instruction (generated
by the compiler when the end of the function is reached) pops this
address from the stack and jumps to it to continue the execution from
that point.
Notice that we pushed the parameters on the stack, but didn't pop them.
This is because, except in the CDECL calling convention, cleaning up the
parameters is responsibility of the called function, not the caller. To
clean up the parameters, the RET instruction is used with an operand
indicating the number of bytes ESP should be incremented, 8 in this case
(ESP was decremented 4 bytes per parameter when they were pushed). The
compiler takes care of this, so we don't have to bother about it, but if
you see the CPU debug window and you wonder what's that RET $08, now you
know what it is.
Upon entry to Sum, the stack would in theory like this:
| |
+-----------+
| Ret_Addr | <- ESP
+-----------+
| $00000005 | (parameter e)
+-----------+
| $00000004 | (parameter d)
+-----------+
| |
When a function has parameters in the stack (or local variables), the
compiler generates a few instructions that are called a "stack frame".
Upon entry to the function (in the "asm"), EBP is pushed on the stack
(to preserve it) and ESP is assigned to it, and before leaving the
function (in the "end;"), the original value of EBP is popped from the
stack:
function Sum(a, b, c, d, e: integer): integer;
asm // push ebp; mov ebp, esp;
....
end; // pop ebp; ret 8;
Thus, when we enter Sum, the stack would actually look like this:
| |
+-----------+
| Orig. EBP | <- EBP, ESP
+-----------+
| Ret_Addr |
+-----------+
| $00000005 | <- EBP+8 (parameter e)
+-----------+
| $00000004 | <- EBP+12 (parameter d)
+-----------+
| |
At [EBP] we find the original value of EBP that was pushed on the stack
to preserve it when building the stack frame, at [EBP+4] we find the
return address of the procedure, and at [EBP+8] we have the last
parameter (the last parameter is pushed last, and therefore it's the
first on the stack). The next parameter (right to left) is at [EBP+12]
and so on if we had more parameters.
Now let's write the function Sum in assembler:
function Sum(a, b, c, d, e: integer): integer;
{
begin
Result := a + b + c + d + e;
end;
}
asm
add eax, b
add eax, c
add eax, d
add eax, e
end;
Notice that in the asm..end block we used "b", "c", "d" and "e" instead
of "EDX", "ECX", "[EBP+12]" and "[EBP+8]" respectively. We can do that
because the compiler will make the appropriate substitutions.
Local variables on the stack
----------------------------
If our function has local variables, in complete inline assembler
functions the compiler will make space for them in the stack moving the
stack pointer, so the stack frame for a function with two integer local
variables would look like this:
push ebp
mov ebp, esp
sub esp, 8 // Moves ESP as if we pushed 8 bytes
...
add esp, 8 // Moves ESP as if we popped 8 bytes
pop ebp
For the purpose of the example, here is a variant of the Sum function
introduced above, but using two local variables:
function SumL(a, b, c, d, e: integer): integer;
var
f, g: integer;
{
begin
f := b + c;
g := d + e;
Result := a + f + g;
end;
}
asm // push ebp; mov ebp, esp; sub esp, 8;
add edx, ecx
mov f, edx // b + c
mov edx, d
add edx, e
mov g, edx // d + e
add eax, f
add eax, g
end; // add esp, 8; pop ebp; ret 8
Within this function, the stack would look like this:
| |
+-----------+
| var. g | <- EBP-8, ESP
+-----------+
| var. f | <- EBP-4
+-----------+
| Orig. EBP | <- EBP
+-----------+
| Ret_Addr |
+-----------+
| Param e | <- EBP+8
+-----------+
| Param d | <- EBP+12
+-----------+
| |
What's next
===========
In the continuation of this article we'll learn more instructions, and
we'll see how to pass and return other kind of parameters, how to work
with arrays, how to access record and object fields, how to call
methods, and more.
________________________________________________________________________
6. FORUMS
Delphi
======
If you know a lot about Delphi but you are still far from being a guru
this forum is for you. This is the only forum for intermediate-level
Delphi programmers on the Web (Delphi experts are also welcome :-)). The
forum now has more than 700 members and during April had traffic of just
over 450 messages:
http://groups.yahoo.com/group/delphi-en
If you want to join the group, the best way is to subscribe from the
web since you can access the special features available at the web site
(a Yahoo! ID is required and you can get yours free by registering as a
Yahoo! user) but if you don't want to register or if you don't have full
Internet access you can also subscribe by email:
http://groups.yahoo.com/group/delphi-en/join
delphi-en-subscribe@yahoogroups.com
Components
==========
This is a forum for searching/recommending software components (VCL and
CLX components, ActiveX objects, DLL libraries, shared objects, etc.),
as well as utilities, tutorials, information, etc. The forum is rather
new and currently has about 175 members and very low traffic:
http://groups.yahoo.com/group/components
I hope you join the forum to help us build a larger group. You can
subscribe from the web or --more easily-- by email:
http://tech.groups.yahoo.com/group/components/join
components-subscribe@yahoogroups.com
Software Developers
===================
This is a forum for discussions about software development and to share
experience in the work, professional or commercial environments. It is
not a programming forum, matters treated here are supposed to be more
general or language independent. The forum is rather new and currently
has about 160 members and very low traffic:
http://groups.yahoo.com/group/software-developers
I hope you join the forum to help us build a larger group. You can
subscribe from the web or --more easily-- by email:
http://tech.groups.yahoo.com/group/software-developers/join
software-developers-subscribe@yahoogroups.com
________________________________________________________________________
7. DELPHI ON THE NET
By Dave Murray <irongut @ vodafone.net>
Components, Libraries and Utilities
===================================
Shareware/Commercial
--------------------
* llPDFLib v1.1 - by llionsoft, Shareware ($70, $280 with source)
llPDFLib is pure Object Pascal library for creating PDF documents.
Does not use any DLL and external third-party software to generate PDF
files. Library consists of TPDFDocument component with properties and
methods like Delphi's TPrinter but designed to generate a PDF file.
http://www.llion.net/
* TPasScript v6.52 - Alexander Baranovsky, Shareware($80) (DELPHI/KYLIX)
An interpreter of the Object Pascal language which supports all Object
Pascal data types except interfaces. The TPasScript component allows
you to embed the interpreter into your Delphi application, so you can
extend and customize the application without having to recompile it.
Using TPasScript you can: write and run scripts, call script-defined
routines, call routines in a dll, import Delphi-defined classes,
routines and variables.
http://www.paxscript.com/
* MaxSpace - by Zecos Software, Shareware ($15)
MaxSpace makes using Delphi and C++ Builder more comfortable It turns
the IDE ToolBar and ObjectInspector into autohide toolbars, giving you
unbelievable freedom for program editing and form designing.
http://www.zecos.com/maxspc
Freeware
--------
* TRealSpinEdit v1.1 - Igor Popov, FREEWARE with source (DELPHI/KYLIX)
Based on Visual C++ TSpinEdit, for all who need Value to be a float
type. Now with negative value support.
http://igp.dax.ru
* FastReport CLX v2.46 - A Tzyganenko, FREEWARE w source (DELPHI/KYLIX)
The first powerful cross-platform report generator for Delphi + Kylix.
Create highly efficient cross-platform reports for with a minimum of
coding. Development environment includes: Visual Report Designer,
Visual Dialog Designer, Object Inspector, and Component Palette.
http://www.fast-report.com
* DBDateTimePicker - by Stefano Carfagna, FREEWARE with source
Database aware DateTimePicker component for "DateTime" fields.
http://www.data-ware.it
* LIBXML libxml2 v2.4.21 - by Delphree, FREEWARE w source (DELPHI/KYLIX)
Pascal units accessing the popular XML API from Daniel Veillard
(http://www.xmlsoft.org). Usable from Kylix and Delphi and hopefully
also from other Pascal compilers like FreePascal.
http://sourceforge.net/projects/libxml2-pas/
* LIBXML libxslt v1.0.17 - by Delphree, FREEWARE w source (DELPHI/KYLIX)
Pascal units accessing the popular XML API from Daniel Veillard
(http://www.xmlsoft.org). Usable from Kylix and Delphi and hopefully
also from other Pascal compilers like FreePascal.
http://sourceforge.net/projects/libxml2-pas/
* Key Objects Library v1.27 - by Delphree, FREEWARE with source
Based on experience aquired on eXtreme Class Library project. Main
purpose is to create smaller programs using Delphi environment.
http://bonanzas.rinet.ru/
* DARTH: C-to-Pascal header converter - by JEDI, FREEWARE with source
Source compiles into a tool that parses C headers and generates Delphi
source for Windows API calls.
Articles, tips and tricks
=========================
* The Future of the Borland Database Engine (BDE) and SQL Links
The Borland RAD Team reveals plans for future database access in
Delphi and C++Builder. You need to read this if you haven't already!
http://community.borland.com/article/0,1410,28688,00.html
* Top Picks: Reporting Tools - by Zarko Gajic
Easily create complex reports that are linked directly into your EXE.
Most of the tools from this list provide all the means for you to
develop reports including a report engine, designer, previewer, etc.
http://delphi.about.com/library/toppicks/aatpreporting.htm
* GDI Graphics in Delphi - by Alistair Keys
From simple lines to direct API calls: the ultimate tutorial to GDI
graphics in Delphi. Look for: drawing lines and shapes, flicker-free
drawings, off-screen bitmaps, GDI drawings the API way...
http://delphi.about.com/library/bluc/text/uc052102a.htm
* Choosing the best Help Format for your project - by Meredith Little
No developer wants to work on documentation but it is a necessary
evil. This article explores the concept of developing help and
describes the available help formats.
http://builder.com.com/article.jhtml?id=u00220020429lit01.htm
* Choose the right Tool for creating Online Help - by Meredith Little
Creating online help is often seen as a burden, but many tools are
available to simplify the process. Here's a look at some choices.
http://articles.techrepublic.com.com/5100-10878_11-5035298.html
* Functional vs. Design in documentation - by William T. Kelly
Do you need a design or functional specification? It depends on who
your audience is and where you are in the product development cycle.
http://builder.com.com/article.jhtml?id=u00420020503WTK01.htm
* How to get the text of a StatusBar?
http://www.swissdelphicenter.ch/en/showcode.php?id=935
* How to make a polygon hole on a form?
http://www.swissdelphicenter.ch/en/showcode.php?id=995
* How to get the associated icon of a file shortcut?
http://www.swissdelphicenter.ch/en/showcode.php?id=1108
* How to list all Subdirectories of a Directory?
http://www.swissdelphicenter.ch/en/showcode.php?id=1125
* How to get the Windows Version?
http://www.swissdelphicenter.ch/en/showcode.php?id=1126
* How to color text in a TRichEdit?
http://www.swissdelphicenter.ch/en/showcode.php?id=1129
* How to use the IP Address Control in a Form?
http://www.swissdelphicenter.ch/en/showcode.php?id=1132
* How to display the exported Dll functions?
http://www.swissdelphicenter.ch/en/showcode.php?id=1133
* How to display the 'Choose Computer' dialog?
http://www.swissdelphicenter.ch/en/showcode.php?id=1135
* How to use steganography?
http://www.swissdelphicenter.ch/en/showcode.php?id=1139
* How to resolve environment variables?
http://www.swissdelphicenter.ch/en/showcode.php?id=1140
* How to determine, if a Edit field has password characters?
http://www.swissdelphicenter.ch/en/showcode.php?id=1141
* How to determine the user's logon domain?
http://www.swissdelphicenter.ch/en/showcode.php?id=1142
* How to highlight HTML-Tags in TRichEdit?
http://www.swissdelphicenter.ch/en/showcode.php?id=1143
* How to store more than 64 KB in a TRichEdit?
http://www.swissdelphicenter.ch/en/showcode.php?id=1144
* How to select a TreeView node with the right mouse button?
http://www.swissdelphicenter.ch/en/showcode.php?id=1145
* How to assign an event handler to all components?
http://www.swissdelphicenter.ch/en/showcode.php?id=1148
* How to crack a URL into its component parts?
http://www.swissdelphicenter.ch/en/showcode.php?id=1149
* How to delete the 'Temporary Internet Files'?
http://www.swissdelphicenter.ch/en/showcode.php?id=1150
* How to get the windows file type?
http://www.swissdelphicenter.ch/en/showcode.php?id=1153
* How to get the grayscale from a RGB color?
http://www.swissdelphicenter.ch/en/showcode.php?id=1154
* How to convert a partition/file size to a String?
http://www.swissdelphicenter.ch/en/showcode.php?id=1155
* How to detect the default smtp mailserver?
http://www.swissdelphicenter.ch/en/showcode.php?id=1156
* How to implement Forward/Back/Cancel buttons in TWebbrowser?
http://www.swissdelphicenter.ch/en/showcode.php?id=1158
* How to format Seconds as (hh:mm:ss)?
http://www.swissdelphicenter.ch/en/showcode.php?id=1163
* Catch debug information of an application - by Tommy Andersen
Ever wanted to read an application's debug information?
http://www.delphi3000.com/articles/article_3216.asp
* Hide application in Windows 2000 - by Eber Irigoyen
Hiding your application from the taskbar and "Applications".
http://www.delphi3000.com/articles/article_3220.asp
* Retrieve email addresses from Outlook mails - by Alain Godinas-Andrien
http://www.delphi3000.com/articles/article_3222.asp
* Maping / Unmaping virtual drives - by Eber Irigoyen
Two functions that let you create Virtual Drives for commonly used
folders (local or network folders) so they appear on "My Computer" as
a new drive for quick access. Like DOS SUBST command.
http://www.delphi3000.com/articles/article_3224.asp
* What Custom Compiler messages can do for you - by Yoav Abrahami
Create reminders that generate compiler warnings and errors.
http://www.delphi3000.com/articles/article_3228.asp
* How do you subclassing a versatile TList? - by Max Kleiner
You can use a TList almost for everything, so an own class leads to
better design and maintainability so this article shows how and why.
http://www.delphi3000.com/articles/article_3229.asp
* Modifying Contents of the Taskbar from Delphi - by Igor Kurilov
Using ITaskbarList interface.
http://www.delphi3000.com/articles/article_3230.asp
* Easy Parsing an XML File - by Max Kleiner
How do you get the elements from an XML file? Using MS XML DOM parser.
http://www.delphi3000.com/articles/article_3231.asp
* Using Autohint - by David Knight
Using hints without the flybys that cover data and often annoy users.
http://www.delphi3000.com/articles/article_3234.asp
* Function DBGridToHtmlTable - by Zswang Wangjihu
http://www.delphi3000.com/articles/article_3236.asp
* Loading resources from DLL files - by Martin Strand
http://www.delphi3000.com/articles/article_3238.asp
* Getting System Power Information - by Magnus Flysjö
Reteriving battery information for notebooks.
http://www.delphi3000.com/articles/article_3241.asp
* Is font "X" installed? - by Eber Irigoyen
http://www.delphi3000.com/articles/article_3242.asp
* Get the application associated to an extension - by Eber Irigoyen
http://www.delphi3000.com/articles/article_3243.asp
* DLL in Dephi to be called from Visual Basic - by Khaled Shagrouni
Creating a DLL in Dephi to be called from another language like VB.
http://www.delphi3000.com/articles/article_3244.asp
* Get the Number of Print Jobs - by Andreas Schmidt
Get the number of jobs in the windows spooler for a specific printer.
http://www.delphi3000.com/articles/article_3247.asp
* MySQL without the commonly required components - by Me Me
MySQL the easy way without BDE or ODBC.
http://www.delphi3000.com/articles/article_3248.asp
* Remove horizontal and/or vertical scrollbar of TDBGrid - G Christophe
Get rid of those pesky scrollbars on TDBGrid when you don't need them.
http://www.delphi3000.com/articles/article_3254.asp
Tutorials
=========
* Kylix Tutorial Series - by Brian Long
Ten part tutorial series previously published in Linux Format.
http://www.blong.com/Articles.htm#KylixTut
* Remedial XML: Say HELLO to DOM - by Lamont Adams
Get acquainted with W3C's Document Object Model (DOM) in this part of
the remedial XML series. A language-neutral look at how you can put
this model to work.
http://articles.techrepublic.com.com/5100-10878_11-5147519.html
* A Beginner's Guide to Delphi Programming - by Zarko Gajic
FREE online Delphi programing course for beginners, now up to Part 3.
http://delphi.about.com/library/weekly/aa031202a.htm
Other Links
===========
* VCL Scanner 2002 Sweepstakes winners - by Anders Ohlsson
Thanks to all who participated in the VCL Scanner 2002 project!
http://community.borland.com/article/0,1410,28665,00.html
________________________________________________________________________
YOU CAN HELP US
We need your help to keep this newsletter going and growing. You can
help by referring the newsletter to your colleagues:
http://www.latiumsoftware.com/en/pascal/delphi-newsletter.php
Or you can help by voting for us in some or all of these rankings to
give more visibility to our web site and thus increase the number of
subscriptions to this newsletter:
http://www.programmingpages.com/?r=latiumsoftwarecomenpascal
http://top100borland.com/in.php?who=20
It's just a few seconds for you that REALLY mean a lot to us.
Don't forget we also need articles for this newsletter and there is a
prize for one of the authors in each issue. All articles will be
considered but we are particularly interested in articles about Kylix
because there is so little available online to help Kylix developers.
Send articles to <eds2008 @ latiumsoftware.com>.
We are also looking for shareware authors who would like to offer their
components or applications as prizes for articles in the newsletter. In
return you will be promoted in this newsletter and the Latium Software
web site. For more information contact Dave <irongut @ vodafone.net>.
________________________________________________________________________
If you haven't received the full source code examples for this issue,
you can get them from http://www.latiumsoftware.com/en/file.php?id=p36
________________________________________________________________________
This newsletter is provided "AS IS" without warranty of any kind. Its
use implies the acceptance of our licensing terms and disclaimer of
warranty you can read at http://www.latiumsoftware.com/en/legal.php
where you will also find a note about legal trademarks. Articles are
copyright of their respective authors and they are reproduced here with
their permission. You can redistribute this newsletter as long as you do
it in full (including copyright notices), without changes, and gratis.
________________________________________________________________________
Main page: http://www.latiumsoftware.com/en/pascal/delphi-newsletter.php
Group home page: http://groups.yahoo.com/group/pascal-newsletter/
Subscribe/join: pascal-newsletter-subscribe@yahoogroups.com
Unsubscribe/leave: pascal-newsletter-unsubscribe@yahoogroups.com
Problems with your subscription? eds2008 @ latiumsoftware.com
________________________________________________________________________
Latium Software http://www.latiumsoftware.com/en/index.php
Copyright (c) 2002 by Ernesto De Spirito. All rights reserved.
________________________________________________________________________
|