Pascal Newsletter #49
The full source code examples of this issue are available for download.
![]() |
![]() |
Pascal Newsletter #49 - 29-SEP-2003 Contents 1. A few words from the editor 2. Class Attributes - The Delphi Way 3. Creating a Delphi Expert The simplest way of creating a Delphi Expert 4. Inside Delphi's Classes and Interfaces (I) 5. Forums / mailing lists 6. Delphi on the Net - Components, Libraries and Utilities · Shareware/Commercial · Freeware · Delphi and Borland Product Updates - Articles, Tips and Tricks - Tutorials and Training - Other Links - News ________________________________________________________________________ 1. A few words from the editor I'm happy to announce the newsletter has reached 10,000 subscribers. Special thanks to all the subscribers who made it possible by referring the newsletter to their colleagues, and also to all the webmasters who exchanged links with us, allowing the web site to be known in the Delphi community. In this issue we have an article by Demian Lessa showing a way to implement class attributes in Object Pascal, an article by Daniel Wischnewski explaining how to create a simple Delphi Expert, and an article by Ezra Hoch revealing the inner workings of classes and interfaces. Thanks to the authors for contributing their articles for this issue, and the prizes available for this issue go to: * Demian Lessa ("Class Attributes - The Delphi Way") · NTTools 7 For Delphi - by i-tivity (US$ 49.95) Stop battling the Windows NT Security API! Get your copy of NTTools 7 for Delphi 4/5/6/7 now and save countless hours with this collection of 40 VCL components written specifically to deal with the Windows NT Security functions. Full source code is included. http://www.i-tivity.biz/nttools.htm * Daniel Wischnewski ("Creating a Delphi Expert") · LMD SearchPack 2.0 - by LMD Innovative (EUR 39) LMD SearchPack includes 3 controls for integrating advanced text search capabilities into your projects including support of AND, OR, NEAR and NOT operators. Full source code and extensive demo projects included. http://www.ceberus.com/lmd/products/index.php3#P6 For the next issue, we have available the following prizes for two of our contributors: * EurekaLog v4.1.1 - by Fabio Dell'Aria (Std $24, Pro $49, Ent $99) EurekaLog gives your application (GUI, Console, Web, etc.) the ability to catch every exception, generate a detailed log (with unit, class, method and line #) and send it via email. Fully integrated into the IDE, you only need a single rebuild to add EurekaLog to your apps. Does not decrease performance and increases compiled file size by just 0.5% - 4%. Compatible with Delphi 3 - 7 and all Windows platforms. http://www.eurekalog.com/bannerclick.php?id=15 * SMExport v4.30 - by Scalabium Software ($20 standard, $35 with source) Native VCL suite for exporting data from different sources (dataset, grids, decision cube, memory, DevExp trees, etc). Supports export into MS Excel, MS Access, MS Word, PDF, Text/CSV, HTML, XML, dBase, RTF, SQL, Lotus 1-2-3, QuattroPro and more. http://www.scalabium.com/ The link to the updated Kylix 3 fixes published in the last issue was incomplete. Thanks to Chris Nye for letting us know the correct link is http://codecentral.borland.com/codecentral/ccweb.exe/listing?id=20136 After the publication of my article "Playing sounds with the PC speaker" in the last issue, many people asked me about generating sounds thru the PC speaker under Windows NT/2000/XP. Under these operating systems, the Windows API Beep accepts as arguments the frequency of the sound (in hertz) and duration (in milliseconds), which are ignored under Windows 95/98/Me. Well, this is it. I hope you enjoy this issue. Regards, Ernesto De Spirito eds2004 @ latiumsoftware.com __________________ Collaborated in this issue: Dave Murray ________________________________________________________________________ Help & Manual 3, by EC Software - Shareware ($ 279) - Help & Manual is a WYSIWYG help authoring tool that will aid you in creating standard WinHelp files (.HLP), Adobe PDF files, HTML pages and the new HTML HELP (.CHM) files introduced in Windows 98, as well as other file formats and printed documentation, everything from a single source. This is a must- have for any software developer. http://www.helpandmanual.com/hmpage.htm ________________________________________________________________________ 2. Class Attributes - The Delphi Way By Demian Lessa <demian @ knowhow-online.com.br> On a recent discussion about class attributes on the delphi-br forum on Yahoo! Groups, I had the chance to learn a new technique that allows the practical implementation of class attributes in Delphi. But, what are class attributes anyway? Class attributes are values associated with a class itself and not its instances. In other words, the class attribute value is the same across all class instances. And how are class attributes useful? I can suggest two very obvious utilities: class instance counting, and association of an object instance to the class as a whole (for management purposes). When you need to keep track of the number of instances of a given class you may do so by using a global unit variable on the implementation section- this guarantees that the variable doesn't get changed by code outside the unit. Yet, other portions of code inside the unit (even outside the class) can still change the value of that variable. By encapsulating this value in a class attribute the problem is solved and the instance count can only be changed through proper calls to methods of the class. Another important use of class attributes relates to the use of manager or helper objects. Imagine, for instance, that instead of counting the instances of a class we wish to keep a list of the running instances of our class. All we have to do is define a class attribute to keep a list of the class instances. This list object can be instantiated when needed and destroyed, for example, in the finalization of the unit. This can even be used as the basis for a simple garbage collection mechanism! The implementation of class attributes in Delphi is presented below. The values of the class attributes are hidden inside the class and can only be changed through calls to the proper setter methods. The trick on how to encapsulate the value was presented to me by Marcelo Almeida, one of the moderators of the delphi-br forum on Yahoo! Groups. type TMyClass = class private class function Attribute: PInteger; class function InstanceList: Pointer; class procedure DestroyInstanceList; public constructor Create; class function GetAttribute: Integer; class function GetInstanceList: TObjectList; class procedure SetAttribute(Value: Integer); end; class function TMyClass.Attribute: PInteger; {$J+} const placeholder: Integer = 0; {$J-} begin Result := @placeholder; end; class function TMyClass.InstanceList: Pointer; {$J+} const placeholder: TObjectList = nil; {$J-} begin if (TObjectList(Pointer(@placeholder)^) = nil) then // let us destroy our objects placeholder := TObjectList.Create(false); Result := @placeholder; end; class procedure TMyClass.DestroyInstanceList; begin if (GetInstanceList <> nil) then begin GetInstanceList.Free; TObjectList(InstanceList^) := nil; end; end; class function TMyClass.GetAttribute: Integer; begin Result := Attribute^; end; class function TMyClass.GetInstanceList: TObjectList; begin Result := TObjectList(InstanceList^); end; class procedure TMyClass.SetAttribute(Value: Integer); begin Attribute^ := Value; end; constructor TMyClass.Create; begin inherited Create; SetAttribute(GetAttribute + 1); GetInstanceList.Add(Self); end; destructor TMyClass.Destroy; begin SetAttribute(GetAttribute - 1); GetInstanceList.Remove(Self); if (GetInstanceList.Count = 0) then DestroyInstanceList; inherited Destroy; end; In TMyClass, the class methods Attribute and InstanceList are responsible for encapsulating the values of the class attributes. In these methods, local typed constants ($J+ directive) are used as placeholders for the class attributes. Typed constants can have their values changed in runtime the same way as variables. But the constants we use are local- so, how can they store global values for the class? The answer is pretty simple: we don't use the values of the constants. The constants are declared so the compiler reserves the proper memory for their value types. And, though declared as local, the memory space that the compiler reserves for them (represented by a simple pointer) isn't changed throughout program execution and, therefore, we can use this memory space to implement our class attributes. Clever, huh? The methods Attribute and InstanceList return pointers to the memory reserved by the compiler for the local typed constants. This is the big trick! On the attached code you will find the full source for TMyClass and a small application showing the use of the class attributes of TMyClass. ________________________________________________________________________ When was the last time you voted for the Pascal Newsletter? Please support this initiative voting for us in The Programming Top 100! http://www.sandbrooksoftware.com/cgi-bin/TopSite2/rankem.cgi?id=latium ________________________________________________________________________ 3. Creating a Delphi Expert The simplest way of creating a Delphi Expert Copyright © 2003 Daniel Wischnewski. Visit my company http://www.gatenetwork.com German Version of this article available at http://www.delphipraxis.net/referenzen.php Introduction ============ Sometimes you want to define some routines to make your life easier while using Delphi. A simple way to do this is creating an Expert. This first article shows you the basics. This article introduces you to the world of Delphi Experts. Delphi Experts are DLLs that will be loaded during the startup sequence of Delphi. This article first appeared on Delphi-PRAXiS in German: http://www.delphipraxis.net/viewtopic.php?t=5300 NOTE: The techniques shown in this article are valid starting with Delphi 3 or 4 and since Delphi 7 they are deprecated, however, still fully supported by the Delphi IDE. Installation of a Delphi-IDE-Expert =================================== Every Delphi Expert has to be registered in the Windows Registry. For each Delphi version installed on a machine, as well as for each user using the machine, the Delphi Expert has to be registered separately. In the Registry, the Delphi Expert has to be registered under the following key: HKCU\Software\Borland\Delphi\X.0\Experts where the X has to be replaced by the appropriate Delphi version supported. It may happen that the Experts key is not installed, in such case you are required to create it. Underneath the Experts key you have to create a string value for the Delphi Expert. The name must be unique and the value must point to the expert's DLL, including both complete path and file name of the Delphi Expert. Next time Delphi starts, the Expert will be loaded automatically. The interface of the Delphi Expert ================================== In order for the Delphi Expert to interact with the Delphi IDE it has to export a function with the name ExpertEntryPoint, using the following parameters: function InitExpert( ToolServices: TIToolServices; RegisterProc: TExpertRegisterProc; var Terminate: TExpertTerminateProc): Boolean; export; stdcall; The first parameter ToolServices offers all "documented" interfaces to the Delphi IDE. The second parameter RegisterProc is used to load the expert into the Delphi IDE. The last parameter Terminate is used to notify the Expert DLL when it is about to be unloaded by the Delphi IDE. The InitExpert method returns True if the Expert has loaded successfully, otherwise it can either return False or raise an exception to unload the DLL from the Delphi IDE (see code sample for solution). The PlugIn class TIExpert ========================= Any Delphi Expert must be derived from the class TIExpert, which is declared in the unit ExptIntf. This class defines some abstract methods which must be implemented by each PlugIn: GetName, GetAuthor, GetComment, GetPage, GetGlyph (different for Windows and Linux), GetStyle, GetState, GetIDString, GetMenuText and Execute. The purpose of each method is explained in the source code below. The simplest Delphi Expert ========================== This Delphi Expert won't do much good, however it shows you the basic way of getting the job done. It will show an entry in the Help menu (default behavior). Once the user clicks the menu item, the method Execute from the Expert will be called. The following points must be respected in order to get the expert working: * The method GetState must return [esEnabled] * The method GetStyle must return esStandard * The method GetMenuText returns the text to be shown in the Help menu * The method Execute defines the expert action upon activation The full source code of this simple expert can be found attached. ________________________________________________________________________ Delphi-PRAXiS · Community for German-speaking Delphi programmers. We are not just (one of) the fastest growing German Delphi-forums, but we also offer some unique services like our "Delphi-PRAXiS Expert" (a Delphi add-on which allows access to our libraries directly from within the IDE). In the "code library" you can find several tips, tricks and snippets ready to use. Our database contains more than 50,000 articles for searches of any kind. >>>>>>>> http://www.delphipraxis.net <<<<<<<< ________________________________________________________________________ 4. Inside Delphi's Classes and Interfaces (I) By Ezra Hoch A few words before we start: - First, I want to start this article by saying that all of the knowledge in this paper is derived from viewing the disassembler of Delphi 5. Hence everything written here is valid only for Delphi 5 and might change by any upgrade or different version. - Second, in order to fully understand what is written in this article, you'll have to dive into some assembler code. I'll explain what the assembler code does, but be prepared, it might get messy. And now to the real stuff. In Delphi, a class' instance is a simple pointer. That might seem odd to some people, since you've used instances in Delphi many times and never had to treat them like pointers. That is correct, but only because Borland was kind enough to wrap these pointers nicely up. These pointers actually point to a complicated structure in memory, which we'll try to understand. First, we'll look at a simple class definition: TBoo1 = class FDataA, FDataB : Integer; end; var Boo1 : TBoo1; begin Boo1 := TBoo1.Create; end; Now let's look at what Boo1 points to (Boo1 is a pointer, remember?). Boo1 points to the following values, each 4 bytes long: a Pointer to TBoo1's VMT FDataA FDataB Now let's examine a descendant of TBoo1: TBoo2 = class(TBoo1) FDataC, FDataD : Integer; end; var Boo2 : TBoo2; begin Boo2 := TBoo2.Create; end; Boo2 will point to the following values in memory: a Pointer to TBoo2's VMT FDataA FDataB FDataC FDataD Notice that the values that Boo2 points to include some of the values that Boo1 points to. That's very easy to explain - TBoo2 inherits from TBoo1, therefore it must include all of the fields that TBoo1 has. As a general rule, we can state that each class instance points to the following values: a pointer to the Class' VMT a list of the fields of the parent class a list of the fields of the class Now it's time to investigate interfaces. Before we can fully understand interfaces we must understand the way Delphi makes a method call to a class instance. What Delphi actually does, is call a function with one more parameter than was declared, and that parameter is the instance itself. Let's look at an example: TMoo = class FData: Integer; procedure Act(Value: Integer); end; procedure TMoo.Act(Value: Integer); begin if Self.FData = Value then Self.FData := FData + 1 else Self.FData := Value; end; var Moo: TMoo; begin Moo := TMoo.Create; Moo.Act(15); end; How does Delphi implement this? Simple, 'TMoo.Act' is actually compiled into a procedure that accepts two(!) parameters. One is the defined parameter -'Value' of type integer. The other is an instance of class TMoo. Every time Delphi calls 'Moo.Act' it does some preprocessing beforehand, that is, it passes the instance of TMoo that is making the call. Basically you could say that any call to a method of an object is translated to a regular call to a function / procedure that accepts the object making the call as a parameter. In the previous example, 'TMoo.Act' is actually compiled to something like this: procedure TMoo_Act(Self: TMoo; Value: Integer); begin if Self.FData = Value then Self.FData := FData + 1 else Self.FData := Value; end; It's time to go back to interfaces. Consider the following code: IKoo = interface function Calculate(Value: Integer): Double; end; function Evaluate(Koo: IKoo; Value: Integer): Double; begin Result := Koo.Calculate(Value); end; TKooA = class(TInterfacedObject, IKoo) function Calculate(Value: Integer) : Double; end; TKooB = class(TInterfacedObject, IKoo) procedure DoNothing; function Calculate(Value: Integer): Double; end; Any class that supports IKoo can be passed as a variable to the function 'Evaluate'. When we pass an instance of TKooA to 'Evaluate' we need to call the first method of TKooA, but when we pass an instance of TKooB, we need to call the second method of TKooB! How will Delphi know which function to call at each time?! In order to understand the answer, we must review what an interface really is (and how it is implemented in Delphi). An interface is simply a list of methods that a class declares that it implements. That is, each method in the interface is implemented in the class. The way Delphi implements this is as follows: Each interface a class supports is actually a list of pointers to methods. Therefore, each time a method call is made to an interface, the interface actually diverts that call to one of its pointers to method, thus giving the object that really implements it the chance to act. I'll explain that via the 'Koo' example above: Each time the function 'Evaluate' gets a parameter of type IKoo, it really gets a list (with 4 items - IKoo inherits from IUnknown) of pointers to methods. If it got an IKoo interface that was implemented by TKooA, then the 4th item in the pointer-to-method list would point to 'TKooA.Calcualte'. Otherwise it would point to 'TKooB.Calcualte'. Therefore, when a call is made to 'IKoo.Calculate' what actually is called is what 'IKoo.Calcualte' points to (either 'TKooA.Calculate' or 'TKooB.Calculate'). This is how Delphi implements interfaces. And now to how Delphi stores interfaces in memory. For each instance of a class that supports 'N' interfaces, we need 'N' different lists of pointer-to-method (one for each interface). But these lists are the same in the scope of a single class, therefore, in order to save memory, we only hold 'N' pointers to these lists for each instance (instead of the lists themselves). Consider the following code: ILooA = interface end; ILooB = interface end; TLoo = class(TInterfacedObject, ILooA, ILooB) FLooA, FLooB: Integer; end; This is how an instance of TLoo would look in memory: a pointer to TLoo's VMT FRefcount IUnknown FLooA FLooB ILooB ILooA In general, any class instance would look like this: a pointer to the class' VMT the parent's class' structure (except for the pointer to the VMT) first data member of the class . . last data member of the class last interface in the class' interface list . . first interface in the class' interface list As I said at the beginning of this article, in order to really grasp the way Delphi implements classes and interfaces we must look at the assembler code Delphi produces. First we'll learn a bit of assembler in order to understand the code that will follow. In assembler there is a thing called 'Register'. A register is a place in the CPU that can hold a 32 bit value. On a Pentium CPU there are 8 main registers (EAX, EBX, ECX, EDX, ESI, EDI, EBP, ESP). Most actions that are done in assembler are done on registers. Here are a few commands in assembler: (Moves the value into the register) Mov Register, Value (Moves the value in Register2 into Register1) Mov Register1, Register2 (Moves the value that Register2 points to into Register1. This is the same as the following code: "Register1 := Register2^;") Mov Register1, [Register2] (Moves the value that Register2 + Value points to into Register1. The same as: "Register1 := Pointer(Integer(Register2) + Value)^;") Mov Register1, [Register2 + Value] Examples: MOV EAX, 10 MOV EBX, EAX MOV EAX, [EBX + 6] EBX will hold the value 10 and EAX will hold the value that is in the address $10. Just in order to make sure that you understood this part, I'll give an example of how Delphi assigns a value to an instance's data member. TGoo = class FDataA, FDataB: Integer; end; var Goo: TGoo; begin Goo := TGoo.Create; Goo.FDataA := 5; Goo.FDataB := 7; end; If you'd open Delphi's disassembler you'd see the following code: // Goo.FDataA := 5; mov eax, [ebp-$08] mov [eax + $04], $00000005 // Goo.FDataB := 7; mov eax, [ebp-$08] mov [eax + $08], $00000007 Why move the value pointed by "ebp-$08"? Simple, that's where the variable Goo is stored. Notice that accessing FDataA is the same as accessing the address at "eax+$04" and that accessing FDataB is the same as accessing the address at "eax+$08". That's because the address "eax" points to is the pointer to the VMT of TGoo, and (as I mentioned before) the following values in memory are the data members of TGoo. Let's go back to interfaces. Look at the following code: IRoo = interface end; TRoo = class(TInterfacedObject, IRoo) end; var Roo: TRoo; RooIntf: IRoo; begin Roo := TRoo.Create; RooIntf := Roo; RooIntf._AddRef; end; The following assembler code isn't exactly what Delphi produces but it does the same and serves the purpose: // RooIntf := Roo; // eax holds the value returned by TRoo.Create, i.e. the variable Roo // ecx holds the value that should later be assigned to RooIntf mov ecx, eax // This is the same as: "ecx := ecx + $0C;" add ecx, $0C // RooIntf._AddRef // Push "ecx" onto the CPU's stack push ecx mov ecx, [ecx] // "call ecx" tells the CPU to jump to the address stored as a value // in "ecx" call ecx Let's look at the code that "call ecx" brought us to: // POP the value we pushed onto the stack into "ecx" pop ecx // Same as: "ecx := ecx - $0c;" sub ecx, $0C // Call the method "_AddRef" with "ecx" as a variable. call TInterfacedObject._AddRef(ecx) A little explanation is due. Why did Delphi add "$0C" to "ecx"? Remember how Roo is stored in memory (a pointer to VMT, FRefCount (of InterfacedObject), IUnknown (of TInterfacedObject), IRoo). IRoo is the fourth value in the list that "ecx" points to. Each value is 4 bytes long, so IRoo is 12 (4*4) bytes after "ecx", and "$0C" is 12 in hexadecimal notation. So, basically, adding "$0C" to "ecx" just made "ecx" point to the right value, that is, to point to IRoo of Roo (an instance of TRoo). Why do we push ecx into the stack? That's because we'll need to use it later, when calling the real "_AddRef" method. Remember, "ecx" is the value pointing to Roo + 12. After that, we move into "ecx" the value that "ecx" pointed to. Remember when I said that instead of holding the lists of pointer-to-method, Delphi stores only the pointers to them (to save memory)? That's why "ecx" was actually a pointer, but now it holds the value it pointed to before. The next command, is to call the method that "ecx" holds. Now we'll look at that method. It's very short. The only thing it does is modify the value of "ecx" (after popping it from the stack) so it is equal to the value of Roo (that is, it points to the variable Roo). Then the method 'TInterfacedObject._AddRef' is called with "ecx" (Roo) as a parameter. This is the same as when I've written that Delphi actually compiles a class' method into a regular function / procedure that accepts one extra parameter - the instance of the class. What was that good for? We added a value from a pointer, then did this jump around in memory, then subtracted the same value from the pointer and called the function the pointer points to! Why bother? We could simply call the function without adding and subtracting values! This is where the power of indirection comes into the game. Notice that the call to 'RooIntf._AddRef' didn't know that RooIntf was actually of an instance of TRoo. It just called the method that was there to call. The implementation of this method is where the reassigning of the value of the pointer was made. That is, only the implementation that RooIntf points to (IRoo of TRoo) knew how much was added or subtracted from the pointer pushed to the stack. If we had another variable of type TRoo2, that also implemented IRoo, and we would have made the following assignment 'RooIntf := variable of type TRoo2', and would have called the method 'RooIntf._AddRef', then a different value would be subtracted from the value in the stack, thus making the method call go to the right place in the TRoo2 class. __________________ The author can be reached at ezra.hoch@saad.org.il ________________________________________________________________________ Vote for the Pascal Newsletter in The Programming Pages! http://www.programmingpages.com/topsite.asp?r=latium&Language=29 ________________________________________________________________________ Delphi BUGS? Catch & Log every BUG showing Unit, Class, Method, Line #. Now with support for IntraWeb applications and Anti-Freeze feature. http://www.eurekalog.com/bannerclick.php?id=15 ________________________________________________________________________ 5. Forums / mailing lists To join any of our forums, the best way is to subscribe from the web, since that way you'll be able to access the features available at the web site (like changing your subscription options, viewing the past messages, accessing the files section, etc.). A Yahoo! ID is required for that, 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 (you'll only have email access). * Delphi (intermediate level): If you know a lot about Delphi but you are still far (or not so far) from being a guru, then this forum is for you. This is the only forum for intermediate-level Delphi programmers on the Web... Delphi experts are also welcome! :-) http://groups.yahoo.com/group/delphi-en/ Subscription: http://groups.yahoo.com/group/delphi-en/join delphi-en-subscribe@yahoogroups.com * Delphi (all levels): A Delphi group open to all levels. http://groups.yahoo.com/group/delphi-all/ Subscription: http://groups.yahoo.com/group/delphi-all/join delphi-all-subscribe@yahoogroups.com * Delphi-PRAXiS Forum, for GERMAN-speaking Delphi programmers. http://www.delphipraxis.net/ * Kylix: Kylix programming. http://groups.yahoo.com/group/KylixGroup/ Subscription: http://groups.yahoo.com/group/KylixGroup/join KylixGroup-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. http://groups.yahoo.com/group/components/ Subscription: http://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. http://groups.yahoo.com/group/software-developers/ Subscription: http://groups.yahoo.com/group/software-developers/join software-developers-subscribe@yahoogroups.com ________________________________________________________________________ Merlin's Delphi Forge Delphi and Kylix news, FAQ, downloads, links, forums and more. Accepting uploads and submissions. http://www.delphifaq.net/ ________________________________________________________________________ 6. Delphi on the Net By Dave Murray <irongut @ vodafone.net> Components, Libraries and Utilities =================================== Shareware / Commercial ---------------------- * LMD SearchPack 2.0 - by LMD Innovative (EUR 39) LMD SearchPack includes 3 controls for integrating advanced text search capabilities into your projects including support of AND, OR, NEAR and NOT operators. Full source code and extensive demo projects included. http://www.ceberus.com/lmd/products/index.php3#P6 * EurekaLog v4.2 - by Fabio Dell'Aria (Std $24, Pro $49, Ent $99) Gives your application the ability to catch every exception, generate a detailed log and send it via email. Integrated with Delphi 3 - 7, a single rebuild adds EurekaLog to your app. NEW: save modified files on exception; detailed Log when the application freezes; customizable email for every exception; speed and stability improvements. http://www.eurekalog.com/bannerclick.php?id=15 Freeware -------- * WinDowse v5.1 - by Greatis Software (free for non-commercial use) Unique windows analyzer, best Borland's WinSight replacement. Greatis WinDowse is an extremely convenient tool for obtaining necessary technical information about any window. Place a mouse cursor on a window, and WinDowse will show all parameters of the window and window class. Full Delphi 3-7 source code available after 100 Euro donation. http://www.greatis.com/windowse.htm * Inno Setup v4.0.8 - by JR Software (with source) A free installer for Windows that rivals commercial installers in features and stability. Features include: all 32-bit Windows versions; create a single EXE or disk spanning; standard interface; customizable setup types; complete uninstall capabilities; zip / bzip2 compression; create shortcuts, registry + .INI entries; silent install / uninstall; register DLL, OCX and type libraries; install fonts; Pascal Script. http://www.jrsoftware.org/isinfo.php * TPages v1.2 - by Angus Johnson (with source) Visual component for simple, non-data-aware reports. Features include: text wrapped between margins, in columns or at specific offsets; multiple alignment options; multi-line page headers, footers and column headers; angled text; bitmaps, lines, boxes and arrows; page numbering; prevent blocks of text spanning across pages. http://www.users.on.net/johnson/delphi/ Delphi and Borland Product Updates ---------------------------------- * Fixes for Kylix 3 Issues on Newer Distros (updated) - Andrés Colubri Kylix 3 (particularly C++) on newer Linux distros (eg. RedHat 8+, Madrake 9+, SuSE 8.2) has a number of bugs: compilation errors with STL, unresolved references when linking, installer and IDE hangs, etc. This package contains a collection of fixes to address these issues. http://codecentral.borland.com/codecentral/ccweb.exe/listing?id=20136 Articles, Tips and Tricks ========================= * Come learn about Octane! Sneak peeks around the world! - by A Ohlsson First Octane sighting at Entwickler Konferenz in Frankfurt, Germany. http://bdn.borland.com/article/0,1410,30387,00.html * Using D7 to Consume Web Services and Transform XML - by Anders Ohlsson In this BDNtv episode, Anders shows how you can consume web services that return XML data. Anders uses Delphi 7 Enterprise to create a simple application that consumes an XML web service, transforms the result and displays custom picked data in a regular DBGrid. Format(s): Flash, Duration: 9:34. http://community.borland.com/article/0,1410,30379,00.html * Customizing the DBNavigator Enhancing the TDBNavigator component with modified graphics (glyphs), custom button captions, and more. Exposing the OnMouseUp/Down event for every button. http://delphi.about.com/library/weekly/aa090203a.htm * Accessing and managing MS Excel sheets with Delphi - by Zarko Gajic How to retrieve, display and edit Microsoft Excel spreadsheets with ADO (dbGO) and Delphi. This step-by-step article describes how to connect to Excel, retrieve sheet data, and enable editing of data (using the DBGrid). You'll also find a list of most common errors (and how to deal with them) that might pop up in the process. http://delphi.about.com/library/weekly/aa090903a.htm * Delphi History: from Pascal to Octane - by Zarko Gajic Concise descriptions of Delphi's versions and its history, along with a brief list of features and notes. Find out how Delphi evolved from Pascal to a RAD tool that can help you solve development problems not only for Windows but also for Linux and .NET. http://delphi.about.com/cs/azindex/a/dhistory.htm * Drop Down List Inside a DBGrid: Part 1 - by Zarko Gajic Here's how to place a drop down pick list into a DBGrid. Create visually more attractive user interfaces for editing lookup fields inside a DBGrid - using the PickList property of a DBGrid column. http://delphi.about.com/library/weekly/aa092703a.htm * How to Darken or Lighten TColor? http://www.swissdelphicenter.ch/en/showcode.php?id=1411 * How to execute a Javascript function in a Webbrowser / IE Document? http://www.swissdelphicenter.ch/en/showcode.php?id=1732 * How to display the items in a listview control as a group? (WinXP) http://www.swissdelphicenter.ch/en/showcode.php?id=1782 * How to detect if an Application is running within VMware? http://www.swissdelphicenter.ch/en/showcode.php?id=1819 * How to mix two colors using transparency coefficient? http://www.swissdelphicenter.ch/en/showcode.php?id=1832 * THvHQuery for exporting query to CSV file - by Henk van Hoek Export a query to a Comma Separated CSV File. http://www.delphi3000.com/articles/article_3763.asp * TEdit and EConvertError - by Andrew Kennaugh Checking TEdit for StrToFloat using OnKeyPress not OnChange. http://www.delphi3000.com/articles/article_3765.asp * Inline Assembler in Delphi (I): Introduction - by Ernesto De Spirito Reprinted from this newsletter, Ernesto's Assembler tutorial. http://www.delphi3000.com/articles/article_3766.asp * Inline Assembler in Delphi (II): ANSI strings - by Ernesto De Spirito http://www.delphi3000.com/articles/article_3767.asp * Inline Assembler in Delphi (III): Static Arrays - Ernesto De Spirito http://www.delphi3000.com/articles/article_3768.asp * Inline Assembler in Delphi (IV): Records - by Ernesto De Spirito http://www.delphi3000.com/articles/article_3769.asp * Inline Assembler in Delphi (V): Objects - by Ernesto De Spirito http://www.delphi3000.com/articles/article_3770.asp * Inline Assembler in Delphi (VI): Calling External Procedures - by Ernesto De Spirito http://www.delphi3000.com/articles/article_3771.asp * Inline Assembler in Delphi (VII): 128-bit Integer Arithmetic - by Ernesto De Spirito http://www.delphi3000.com/articles/article_3772.asp * Playing Sounds Thru The Built-In PC Speaker - by Ernesto De Spirito Using inline assembler to play sounds with the built-in PC speaker. http://www.delphi3000.com/article.asp?id=3773 * Determining if a Logical Drive Exists - by Ernesto De Spirito How to know if there is a drive assigned to a letter. http://www.delphi3000.com/articles/article_3774.asp * Using TList's and Pointers in delphi (Part II) - by Stewart Moss Demonstration of how to create records on a TList object. http://www.delphi3000.com/articles/article_3775.asp * Adding HTML Resources to DLL/EXE that IE can Reference - Matt Harrison Creating an RC file to store HTML and Images as resources that works with IE's res:// format. http://www.delphi3000.com/articles/article_3776.asp * Horizontal Modularization - by Hang Liu This article introduces a modular approach to building large applications. http://www.delphi3000.com/articles/article_3777.asp * Borland DataSnap vs Microsof ADO.NET - by Pablo Reyes A comparison between the tools provided by these technologies for building data aware applications. http://www.delphi3000.com/articles/article_3778.asp * Simple Winsock Component for Console App - by J3N7iL Jones How can I create a TCP/IP internet connection in a console application using winsock? http://www.delphi3000.com/articles/article_3779.asp * PageControl Without Border - by Tommy Andersen http://www.delphi3000.com/articles/article_3783.asp * Adding new Standard Actions - by Andreas Schmidt http://www.delphi3000.com/articles/article_3784.asp * Create a Sizeable Dialog - by Terrance Hui How to create a sizable dialog (with sizegrip) without using any 3rd party components. http://www.delphi3000.com/articles/article_3785.asp * Selecting Files - by Teun Spaans In which ways can you let your user choose a file or directory? http://www.delphi3000.com/articles/article_3786.asp * Debugging Tricks - by Andreas Schmidt How to read the content of a TStrings in the integrated debugger. http://www.delphi3000.com/articles/article_3787.asp Tutorials and Training ====================== * BorCon 2003 to be be held in San Jose, California November 1-5, 2003 http://info.borland.com/conf2003/ Other Links =========== * Public Beta: QualityCentral Java Client - by John Kaster Use a smart client for Borland QualityCentral from wherever you can run JDK 1.4.x. http://community.borland.com/article/0,1410,30348,00.html * San Francisco East Bay Delphi User Group Our goal is to connect the Delphi developers in the Bay Area. We meet the 1st Wednesday of every month and have great speakers and sessions. We organize Delphi events with the help of eBig - the East Bay IT Group (www.ebig.org). The group will explore Delphi and how Borland's Delphi 7-8 Studio provides a migration path to Microsoft .NET for developers as well as Delphi and Linux (Kylix). http://www.ebig.org/sig/sig.aspx?SIGid=20 News ==== * Altova XMLSPY to be Included in Borland Development Tools Special Edition of Altova XMLSPY Available in Borland Delphi Studio, C++ Builder, and C# Builder for the Microsoft .NET Framework. http://www.altova.com/press/2003-08-28_borland.pdf ________________________________________________________________________ Vote for the Pascal Newsletter in The Delphi Top 200! http://top200.jazarsoft.com/delphi/rank.php3?id=latium ________________________________________________________________________ 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.sandbrooksoftware.com/cgi-bin/TopSite2/rankem.cgi?id=latium http://news.optimax.com/delphi/links/links.exe/click?id=70C517ECAE6E http://www.programmingpages.com/?r=latiumsoftwarecomenpascal http://www.top219.org/cgi-bin/vote.cgi?delphi&83 http://top100borland.com/in.php?who=20 http://top200.jazarsoft.com/delphi/rank.php3?id=latium http://213.65.224.200/cgi-bin/toplist.cgi/hits?Id=80 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 <eds2004 @ 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/download/p0049.zip ________________________________________________________________________ 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 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? eds2004 @ latiumsoftware.com ________________________________________________________________________ Latium Software http://www.latiumsoftware.com/en/index.php Copyright (c) 2003 by Ernesto De Spirito. All rights reserved. ________________________________________________________________________ |
The full source code examples of this issue are available for download.
![]() |
Errors? Omissions? Comments? Please contact us!






