Pascal Newsletter #51
The full source code examples of this issue are available for download.
![]() |
![]() |
Pascal Newsletter #51 - 12-OCTOBER-2004 Contents 1. A Few Words From the Editors 2. How to Run a Single Instance of an Application (Part 2) 3. Inside Delphi's Classes and Interfaces (Part 2) 4. Forums / Mailing Lists 5. Delphi on the Net - Components, Libraries and Utilities - Shareware / Commercial - Freeware - Borland Product Updates - Articles, Tips and Tricks - Tutorials and Training - News ________________________________________________________________________ 1. A Few Words From the Editors Welcome to another issue of the Pascal Newsletter. As usual we'd like to thank the authors who contributed articles for this issue, Peter Johnson and Ezra Hoch. And, we're pleased to award Ezra the prize for this issue: * Ezra Hoch - 'Inside Delphi's Classes and Interfaces' Delphi SWF SDK (Standard) v1.4 - by FeatherySoft ($170) Object Pascal library for creating SWF files, without using of any external dynamic libraries. Released features: visual objects (shape, button, text, morphing shape, sprite); all types of filling (solid, gradient, image); device and embedding fonts; action commands; sound (events, streaming); video; any transition and transformation. http://www.delphiflash.com/ In the next issue we have two prizes up for grabs. We don't have any submissions yet and can't publish without your help so why not write an article and get yourself some quality tools at the same time as supporting your favourite newsletter. Those prizes include: * KylixDriver v1.1 - by ET Kimberliteware Ltd ($39 / $69 with source) KylixDriver is a RAD Kylix-oriented and integrated toolkit for PC hardware access. This toolkit can be efficiently used for writing Linux device drivers for ISA and PCI hardware. http://www.geocities.com/etkimberliteware/kylixdriver/index.html We are also looking for shareware authors who would like to offer their components or applications as prizes. In return you will be promoted in the newsletter and on the Latium Software and Irongut's Delphi Pages websites. Late Breaking News: Today Borland announced Delphi 2005 (Diamondback) will ship in November. See 'Delphi on the Net' for a news link. Thanks for reading, now on to the code... Regards, Dave Murray and Ernesto De Spirito pascal-newsletter-owner@yahoogroups.com __________________ Collaborated in this issue: Peter Johnson and Ezra Hoch ________________________________________________________________________ Help & Manual 3.50 by EC Software - Shareware ($ 299) - 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. How to Run a Single Instance of an Application Part 2: A Re-usable Solution By Peter Johnson, Copyright (c) 2003 <delphidabbler at tiscali dot co dot uk> http://www.delphidabbler.com/ Overview of an Object Oriented Solution --------------------------------------- This section presents an object oriented, extensible, solution to the problem of running a single application instance. The main code is centralised in a single unit (USingleInst.pas) that implements and creates a singleton object (TSingleInst) that manages the single application instance and takes care of sending and receiving parameter data. While TSingleInst provides a name for the main form's window class, the window class name method can (and should) be overridden to provide a unique class name. A watermark can also be provided by overriding a method. Some alteration of the project file and main form file is required, but the changes are not as significant as in the earlier example and the main functionality is isolated in USingleInst.pas. The procedure for enabling single application instance support in a project that uses USingleInst.pas is as follows: * Add USingleInst.pas to the project. * Create a new class derived from TSingleInst and override the methods that return the window class name and (optionally) the watermark. * Register the new class as the one to use when creating the SingleInst singleton object. * Modify the main form and project sources to call the required entry points into the SingleInst object. In the rest of this section we will review the USingleInst unit, then look at how to derive and register a new class from it and finally describe the changes to be made to the project source and main form source files. The USingleInst Unit -------------------- We will review parts of the unit in order. The full source of the unit accompanies this article. Here is the interface part of the unit that declares the class and supporting functions: unit USingleInst; interface uses Windows, Controls, Messages; type TSingleInstParamHandler = procedure(const Param: string) of object; TSingleInstClass = class of TSingleInst; TSingleInst = class(TObject) private fOnProcessParam: TSingleInstParamHandler; // event handler fEnsureRestoreMsg: UINT; // unique message for ensuring restoration protected function WdwClassName: string; virtual: function WaterMark: DWORD; virtual; function FindDuplicateMainWdw: HWND; virtual; function SendParamsToPrevInst(Wdw: HWND): Boolean; virtual; function SwitchToPrevInst(Wdw: HWND): Boolean; procedure EnsureRestore(var Msg: TMessage); dynamic; procedure WMCopyData(var Msg: TMessage); dynamic; public constructor Create; procedure CreateParams(var Params: TCreateParams); function HandleMessages(var Msg: TMessage): Boolean; function CanStartApp: Boolean; property OnProcessParam: TSingleInstParamHandler read fOnProcessParam write fOnProcessParam; end; function SingleInst: TSingleInst; procedure RegisterSingleInstClass(Cls: TSingleInstClass); Reviewing the type declarations first, TSingleInstParamHandler is the type on the OnProcessParam event handler that is triggered for each parameter passed to the application in a WM_COPYDATA message while TSingleInstClass is the class type of the TSingleInst and derived classes. We will cover the class's methods in the implementation section. The only other item worth mentioning now is the fEnsureRestoreMsg field. This is used to store the id of the custom message used to ask an application to restore and display its window. The message id is provided by Windows and guaranteed to be unique. Unfortunately, use of such a message means we can't use a Delphi message handler to handle the message and must resort to intercepting messages from the message loop (see later). Finally the SingleInst function is used to return an instance of the TSingleInst (or descendant) singleton object while RegisterSingleInstClass is used to register the type of class to be used to create the singleton. We will examine the implementation section in segments. Here is the first: implementation uses SysUtils, Forms; var // Globals storing SingleInst singleton and class of SingleInst gSingleInst: TSingleInst = nil; gSingleInstClass: TSingleInstClass = nil; function SingleInst: TSingleInst; begin if not Assigned(gSingleInst) then begin if Assigned(gSingleInstClass) then gSingleInst := gSingleInstClass.Create else gSingleInst := TSingleInst.Create; end; Result := gSingleInst; end; procedure RegisterSingleInstClass(Cls: TSingleInstClass); begin gSingleInstClass := Cls; end; The private global variables gSingleInst and gSingleInstClass store a reference to the singleton object and the type of the singleton object (as registered in RegisterSingleInstClass) respectively. From the implementation of SingleInst it can be seen that the singleton object is created the first time the object is referenced. If a derived object type has been registered this is used to create the singleton, otherwise the base class is used. This means that any derived TSingleInst class needs to be registered before the object is first accessed - it is recommended that RegisterSingleInstClass is called in the initialization section of the unit where the derived class is defined. This also explains why the singleton is not created in this unit's intialization section, since this section would be called before that in the derived classes unit. Moving on to the class definition, we first look at the class constructor which simply registers the custom message with Windows. constructor TSingleInst.Create; begin inherited; fEnsureRestoreMsg := RegisterWindowMessage('USINGLEINST_ENSURERESTORE'); end; There are various "entry points" into the class that must be called from either the main unit or the project file. We will review these next: function TSingleInst.CanStartApp: Boolean; var Wdw: HWND; begin Wdw := FindDuplicateMainWdw; if Wdw = 0 then Result := True else Result := not SwitchToPrevInst(Wdw); end; procedure TSingleInst.CreateParams(var Params: TCreateParams); begin inherited; StrPLCopy(Params.WinClassName, WdwClassName, SizeOf(Params.WinClassName) - 1); end; function TSingleInst.HandleMessages(var Msg: TMessage): Boolean; begin if Msg.Msg = WM_COPYDATA then begin WMCopyData(Msg); Result := True; end else if Msg.Msg = fEnsureRestoreMsg then begin EnsureRestore(Msg); Result := True; end else Result := False; end; The first of these "entry points" is CanStartApp which is called from the project file and indicates whether the application should be started or not. It works in a similar way to the CanStart function in the previous part of this article (Issue #50). The CreateParams method sets up the main form's window class name by updating the form's create parameters. The main form must override its inherited TForm.CreateParamsSingleInst.CreateParams from within that method. The most complex of the "entry point" methods is the HandleMessages method. This intercepts the WM_COPYDATA and the custom fEnsureRestoreMsg from the main form and handles the processing by delegating to WMCopyData and EnsureRestore respectively (see below). This method returns true if it handles the given message and false otherwise. The main form must override the TForm.WndProc method and call SingleInst.HandleMessages from there, calling its inherited TForm.WndProc method if HandleMessages returns false. Let us now examine the protected helper methods. Firstly we have two methods that should be overridden in descendant classes: function TSingleInst.WdwClassName: string; begin Result := 'SingleInst.MainWdw'; end; function TSingleInst.WaterMark: DWORD; begin Result := 0; end; WdwClassName simply returns the name to use as the window class name of the main form. This should be overridden to return something unique to the application. Similarly Watermark returns 0 as the watermark value (watermarks were discussed in the previous part of this article). This should be overridden to some unusual value if watermarks are to be used. Next up are the two message handling helper methods: procedure TSingleInst.EnsureRestore(var Msg: TMessage); begin if IsIconic(Application.Handle) then Application.Restore; if Assigned(Application.MainForm) and not Application.MainForm.Visible then Application.MainForm.Visible := True; Application.BringToFront; end; procedure TSingleInst.WMCopyData(var Msg: TMessage); var PData: PChar; Param: string; begin if TWMCopyData(Msg).CopyDataStruct.dwData = WaterMark then begin PData := TWMCopyData(Msg).CopyDataStruct.lpData; while PData^ <> #0 do begin Param := StrPas(PData); if Assigned(fOnProcessParam) then fOnProcessParam(Param); Inc(PData, Length(Param) + 1); end; Msg.Result := 1; end else Msg.Result := 0; end; Notice that these methods are based closely on the form message handler methods discussed in the previous part of this article except that they are now no longer directly implemented in the form unit. The only significant change is that WMCopyData now triggers the OnProcessParam event rather than calling a hard-wired method to process parameters directly. Finally we examine the three remaining protected methods: function TSingleInst.FindDuplicateMainWdw: HWND; begin Result := FindWindow(PChar(WdwClassName), nil); end; function TSingleInst.SendParamsToPrevInst(Wdw: HWND): Boolean; var CopyData: TCopyDataStruct; I: Integer; DataSize: Integer; Data: PChar; PData: PChar; begin DataSize := 0; for I := 1 to ParamCount do Inc(DataSize, Length(ParamStr(I)) + 1); Inc(DataSize); Data := StrAlloc(DataSize); try PData := Data; for I := 1 to ParamCount do begin StrPCopy(PData, ParamStr(I)); Inc(PData, Length(ParamStr(I)) + 1); end; PData^ := #0; CopyData.lpData := Data; CopyData.cbData := DataSize; CopyData.dwData := WaterMark; Result := SendMessage(Wdw, WM_COPYDATA, 0, LPARAM(@CopyData)) = 1; finally StrDispose(Data); end; end; function TSingleInst.SwitchToPrevInst(Wdw: HWND): Boolean; begin Assert(Wdw <> 0); if ParamCount > 0 then Result := SendParamsToPrevInst(Wdw) else Result := True; if Result then SendMessage(Wdw, fEnsureRestoreMsg, 0, 0); end; These methods are analogues of equivalent routines in the previous part of this article and won't be further described here. Modifications to the Project File --------------------------------- The project file must undergo a simple change to use the SingleInst object to determine whether or not to start the application. Firstly, the USingleInst should be added to the project and then the project file must be changed to wrap the form creation and application run code in a conditional statement as follows: ... begin if SingleInst.CanStartApp then begin Application.Initialize; Application.CreateForm(TForm1, Form1); Application.Run; end; end. Main Form Modification ---------------------- Slightly more work needs to be done in the main form unit. Firstly, add the following declarations to the form class's protected section: protected procedure WndProc(var Msg: TMessage); override; procedure HandleParam(const Param: string); procedure CreateParams(var Params: TCreateParams); override; Now implement these methods to call into SingleInst as follows: procedure TForm1.CreateParams(var Params: TCreateParams); begin inherited; SingleInst.CreateParams(Params); end; procedure TForm1.WndProc(var Msg: TMessage); begin if not SingleInst.HandleMessages(Msg) then inherited; end; The CreateParams method calls inherited and then calls SingleInst.CreateParams to set the window class name. The overridden WndProc method calls SingleInst.HandleMessages to see if the message is one of the ones handled by SingleInst (the function returns true if it handles a message). If the message was not handled by SingleInst.CreateParams the inherited WndProc method is called to handle it. We will also want to handle the TSingleInst.OnProcessParam event so the application gets notified when parameters are passed through the WM_COPYDATA message. In this example we just add the parameters to a list box. We assign the event handler in FormCreate, where we also process parameters passed to the program when it first starts: procedure TForm1.FormCreate(Sender: TObject); var I: Integer; begin SingleInst.OnProcessParam := HandleParam; for I := 1 to ParamCount do HandleParam(ParamStr(I)); end; procedure TForm1.HandleParam(const Param: string); begin ListBox1.Items.Add(Param); end; Overriding TSingleInst ---------------------- We now look at an example of how to override the TSingleInst. We simply provide a new watermark and a window class name. The whole unit (UMySingleInst.pas) is listed below. The only point of note is how the new class is registered as the class to use for the SingleInst singleton object. unit UMySingleInst; interface uses Windows, USingleInst; type TMySingleInst = class(TSingleInst) protected function WdwClassName: string; override; function WaterMark: DWORD; override; end; implementation { TMySingleInst } function TMySingleInst.WaterMark: DWORD; begin Result := $DE1F1DAB; end; function TMySingleInst.WdwClassName: string; begin Result := 'DelphiDabbler.SingleInst.1'; end; initialization RegisterSingleInstClass(TMySingleInst); end. Conclusion ---------- This article has demonstrated how to ensure that only a single instance of an application is run. It also shows how to pass command line parameters to an already running instance, ensuring its window is displayed prominently. The method used was to detect the presence of the application's main window class among the top level windows. Communication with the previous application instance was by means of messages sent to the instance's main window. In particular, a user defined message was used to ensure the window was restored and visible and the WM_COPYDATA message was used to send the command line parameters across the process boundary. The skeleton of some source code for an application that runs as a single instance was provided. Finally a reusable class was presented that can be used in developing a program that runs only a single instance of the application. A demo application is also included with this issue's source code zip. __________________ Peter Johnson is a hobbyist programmer living in West Wales (UK) who maintains the DelphiDabbler website (http://www.delphidabbler.com/) where his articles and freeware Delphi applications & components are published. A full version of this article is available at: http://www.delphidabbler.com/articles.php?article=13 ________________________________________________________________________ Vote for the Pascal Newsletter in The Borland Top 100! http://top100borland.com/in.php?who=20 ________________________________________________________________________ 3. Inside Delphi's Classes and Interfaces - Part 2 By Ezra Hoch Part 1 of Inside Delphi's Classes and Interfaces was published in the Pascal Newsletter Issue #49. You should read it before this article. http://www.latiumsoftware.com/en/pascal/0049.php#4 In this article we'll finish covering Delphi's implementation of Interfaces, and review a few useful conclusions. Let's start with an indepth example: type IInterface1 = interface procedure ActA; procedure ActB; end; IInterface2 = interface(IInterface1) procedure ActC; procedure ActD; stdcall; end; TSampleClass = Class(TInterfacedObject, IInterface1, IInterface2) procedure ActA; procedure ActB; procedure ActC; procedure ActD; stdcall; end; var Interface1 : IInterface1; Interface2 : IInterface2; Sample : TSampleClass; begin Sample := TSampleClass.Create; Interface1 := Sample; Interface2 := Sample; Interface1.ActA; Interface1.ActB; Interface2.ActA; Interface2.ActB; Interface2.ActC; Interface2.ActD; end; Instead of looking at the compiled code for this example, I'll simlpy note the interesting aspects of it. First, when assigning a value to Interface1, we'd expect Delphi to take the value of what 'Sample' points to and add a specific amount ($10) and be done with it. When assigning a value to Interface2, we'd expect Delphi to do the same, just add a smaller amount ($0C) because the interfaces are stored in memory from the last to the first. But Delphi doesn't do that. It assignes both Interface1 AND Interface2 the value that 'Sample' points to plus $0C. That's because IInterface2 inherites from IInterface1. Therefor, IInterface2 includes IInterface1. Hence, any call to Interface1, will actually be executed through IInterface2's method list. Second, when we call Interface1.ActA, it calls the 4th (every interface inherits from IUnknown) method on IInterface2's method list (because IInterface2 inherits from IInterface1). When we call Interface1.ActB it calls the 5th method on IInterface2's method list. When we call Interface2.ActA it calls the 4th method on IInterface2's method list, just the same as Interface1.ActA. That's because IInterface2 inherits from IInterface1. Third, when we call Interface2.ActD Delphi adds one additional instruction before calling the 7th method of IInterface2. That's because we've declared a different convention call to the method (stdcall). Notice that all of IUnknown's methods are defined with the stdcall directive. The structure of an interface's method list always follows the following rule: First Method . . Last Method The parent's interface's method list In our case, IInterface2's method list is as follows: ActC ActD // IInterface1's method list ActA ActB // IUnknown's method List QueryInterface _AddRef _Release NOTE: The structure above is how the methods' code is organized in memory. The first entry in any interface's method list will belong to QueryInterface (the first method of IUnknown) but it will point to a place in memory (the implementation of that specific interface's QueryInterface method) that is higher than the interfaces' own methods' implementation - as shown in the structure above. In our case, IInterface2's QueryInterface's implementation is higher in memory than IInterface2's ActB's implementation, which is higher in memory than ActD's implementation. Thou ActD is the 7th entry, ActB is the 5th entry and QueryInterface is the 1st entry in IInterface2's method list. To fully understand what happens when Delphi calls an interface's method, lets have a look at the compiled method list of IInterface2 in the example above. The following code is an exact copy of the compiled code (except for the comments): // ActC add eax, -$0C call TSampleClass.ActC // ActD add dword ptr [esp + $04], -$0C call TSampleClass.ActD // ActA add eax, -$0C call TSampleClass.ActA // ActB add eax, -$0C call TSampleClass.ActB // QueryInterface add dword ptr [esp + $04], -$0C call TInterfacedObject.QueryInterface // _AddRef add dword ptr [esp + $04], -$0C call TInterfacedObject._AddRef // _Release add dword ptr [esp + $04], -$0C call TInterfacedObject._Release As you remember, an object's method is actually a regular function or procedure that accepts as a parameter an instance of the method's class. As you can notice, before each call to the real method ('TSampleClass.ActD' for example) there is one line of code that changes the value of either 'eax', or 'dword ptr [esp + $04]', depending on the calling convention. As you can notice, in all cases we subtract $0C form a variable. But, why 12 ($0C = 12) ? That's because this interface (IInterface2) is in the 3rd (FRefcount, IUnknown are before it) place after the pointer to VMT of the clasS TSampleClass. Therefore, the value of any instance of IInterface2 of TSampleClass (Interface2 for example) is actually the value of the pointer to that class' instance plus 12. Here is another example that will help understand the section above. The following code continues the definitions from the above code: type IAnotherInterface = interface procedure ActE; end; TAnotherSample = class(TInterfacedObject, IInterface2, IAnotherInterface) procedure ActA; procedure ActB; procedure ActC; procedure ActD; stdcall; procedure ActE; end; var Interface2: IInterface2; begin Interface2:= TAnotherSample.Create; Interface2.ActC; end; Now, let's compare the entry for this example's IInterface2 and the previous' one: IInterface2 of TAnotherSample: add eax, -$10 call TAnotherSample.ActC IInterface2 of TSampleClass: add eax, -$0C call TSampleClass.ActC There are two obvious changes: a) The actual function that is called (either TAnotherSample.ActC or TSampleClass.ActC) b) The amount that 'eax' is changed by. Notice that when calling IInterface2 of TAnotherSample, 'eax' is changed by 16 ($10 = 16) as opposed to being changed by 12. That's because on TAnotherSample, the IInterface2 is the second interface in the instance's structure in memory, and therefor it is "farther away" from the instance itself and needs to be changed by additional 4 bytes. And now to some useful stuff: First, if you want to check if 2 (or more) interface variables are of the same instance, you cannot simply compare them, even if they are of the same type. You must QueryInterface them to a single interface type, and then compare. As a general rule, if you want to compare interfaces, QueryInterface them to IUnknown and then compare. Example: type IBooA = interface end; IBooB = interface end; TBoo = class(TInterfacedObject, IBooA, IBooB) end; var Boo : TBoo; BooA : IBooA; BooB : IBooB; begin Boo := TBoo.create; BooA := Boo; BooB := Boo; // This won't complie if BooA = BooB then begin Beep; end; if Integer(BooA) = Integer(BooB) then begin // will never get here Beep; end; if IUnknown(BooA) = IUnknown(BooB) then begin // will never get here Beep; end; // the 'as' word is the same as QueryInterface when acting on // interfaces if (BooA as IUnknown) = (BooB as IUnknown) then begin // Will always get here Beep; end; end; Explanation: The first comparing won't compile, because BooA and BooB are of 2 different types. The Second and third comparings will compile but never return true. That's because typecasting doesn't change the value of the variable that's being typecasted. It only allows the compiler to compile the code though there are two different types involved. Hence, if BooA is different from BooB, comparing them will never return true, no matter what type casting is done to them. But why do BooA and BooB have different values ? They were both assigned using the ":= Boo;" statement. The answer is simple. Remember that I said that an interface's variable's value is actually the value of the instance itself (or at least the value of the pointer to the instance) plus a different number for each interface ? In our case, BooA is the same as what Boo points to, added 16. And BooB is the same as what Boo points to, added 12. That's why BooA and BooB are not that same. The Forth comparing actually works. That's because if an interface is from the same type, then comparing it to an interface of that type will always return the expected result (if both interfaces were aquired via QueryInterface, not by type casting). That's because if they are of the same type, then the difference between them and the instance is the same. And if they are of the same instance, then they must be equal. That is, each interface is equal to it's instance + a specific Delta (the Delta depends on the interface). In other words, Interface = Instance + Delta. If 'Instance' is the same for both interfaces, and the 'Delta' is the same (cause they are of the same interface type), then both interfaces must be equal. Note: This is the way Delphi works, for good and for bad. You should take this in mind when writing code for properties of interface type. The following code wouldn't work properly: TSample = class private FData : IUnknown; procedure SetData(Value : IUnknown); protected procedure Changed; virtual; abstract; public property Data : IUnknown read FData write SetData; end; procedure TSample.SetData(Value : IUnknown); begin // This is incorrect. if Value <> FData then begin FData := Value; Changed; end; end; It might seem that this code should work, but it might not work when someone would assign the property 'Data' with an IUnknown retrieved by a type cast. The correct code should be: procedure TSample.SetData(Value : IUnknown); begin if (Value as IUnknown) <> (FData as IUnknown) then begin FData := Value; Changed; end; end; Second, each interface you declare that a class implements (with exception of interfaces that inherit from other interfaces) means that each instance of that class will take up 4 more byte of memory. That might seem like nothing (and probably is) except for one case. Consider the following code: IInterfaceA = interface end; IInterfaceB = interface end; TSampleClass1 = class(TInterfacedObject, IInterfaceA) end; TSampleClass2 = class(TSampleClass1, IInterfaceA, IInterfaceB) end; It would seem that each instance of TSampleClass1 should take up 16 bytes, and each instance of TSampleClass2 should take up 20 bytes (4 bytes more, because it supports one more interface). That is not true. Each instance of TSampleClass1 does take up 16 byte. But, each instance of TSampleClass2 takes up 24 bytes ! That's because Delphi creates an interface entry even for interfaces that are already implemented by parent classes. The solution to this is simple. Just remove the declaration of IInterfaceA from TSampleClass2. This will not change the fact that TSampleClass2 implements IInterfaceA, cause TSamlpeClass2 inherits from TSamlpeClass1, which implements IInterface1. This wouldn't have happened if IInterfaceB was a descendant of IInterfaceA. This might add up to quit a lot if you do your inheritence improperly. For example: TSampleClass1 = class(TInterfacedObject, IUnknown) end; TSampleClass2 = class(TSampleClass1, IUnknown) end; TSampleClass3 = class(TSampleClass2, IUnknown) end; TSampleClass4 = class(TSampleClass3, IUnknown) end; TSampleClass5 = class(TSampleClass4, IUnknown) end; Each instance of TSampleClass5 takes up 32 bytes of memory, though it has no real data (except for FRefCount of TInterfacedObject). ________________________________________________________________________ Delphi-PRAXiS · One of the fastest growing German Delphi-forums, with unique services like our "Delphi-PRAXiS Expert" (add-on which allows access to our libraries directly from within the IDE). Our database contains more than 50,000 articles. >>> http://www.delphipraxis.net <<< ________________________________________________________________________ 4. Forums / Mailing Lists To join any of our forums, the best way is to subscribe from the web, since then you'll be able to access the website features (message archive, files section, etc). A Yahoo! ID is required for that, and you can get yours free by registering as a Yahoo! user, but you can also subscribe by email (you'll only have email access). * Delphi-En: A unique forum for intermediate-level Delphi programmers. A large group with a helpful community of members. If you are a beginner please stay as a listener and learn from others' questions and answers. Home Page: http://groups.yahoo.com/group/delphi-en/ Subscription: http://groups.yahoo.com/group/delphi-en/join delphi-en-subscribe@yahoogroups.com * Delphi-All: A Delphi group open to programmers of all levels. Home Page: http://groups.yahoo.com/group/delphi-all/ Subscription: http://groups.yahoo.com/group/delphi-all/join delphi-all-subscribe@yahoogroups.com * Kylix: Kylix programming. Home Page: 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, .Net, etc.), as well as utilities, tutorials, information, etc. Home Page: http://groups.yahoo.com/group/components/ Subscription: http://groups.yahoo.com/group/components/join components-subscribe@yahoogroups.com * Software Developers: A place for subjects related to software development and the industry. For developers to share their experiences as an academic, professional or hobbyist. It is not a programming forum, messages here are supposed to be more general or language independent. Home Page: http://groups.yahoo.com/group/software-developers/ Subscription: http://groups.yahoo.com/group/software-developers/join software-developers-subscribe@yahoogroups.com ________________________________________________________________________ Vote for the Pascal Newsletter in The Delphi Top 200! http://top200.jazarsoft.com/delphi/rank.php3?id=latium ________________________________________________________________________ 5. Delphi on the Net By Dave Murray <irongut at vodafone dot net> Components, Libraries and Utilities =================================== Shareware / Commercial ---------------------- * KylixDriver v1.1 - by ET Kimberliteware Ltd ($39 / $69 with source) KylixDriver is a RAD Kylix-oriented and integrated toolkit for PC hardware access. This toolkit can be efficiently used for writing Linux device drivers for ISA and PCI hardware. http://www.geocities.com/etkimberliteware/kylixdriver/index.html * Delphi SWF SDK (Standard) v1.4 - by FeatherySoft ($170) Object Pascal library for creating SWF files, without using of any external dynamic libraries. Released features: visual objects (shape, button, text, morphing shape, sprite); all types of filling (solid, gradient, image); device and embedding fonts; action commands; sound (events, streaming); video; any transition and transformation. http://www.delphiflash.com/ Freeware -------- * PGP Components for Delphi v4.0 - Michael in der Wiesche (with source) These sources provide a Delphi (2-7) direct interface to PGP requiring a preceding full installation of PGP 6.5.x, 7.x or 8.x. Features include: Encoding and decoding (encrypt/decrypt/sign/verify); Creating and verifying file detached signatures; Key management; Key generation (DH/DSS, RSA); X509 Certificate support; Keyserver functions. http://home.t-online.de/home/idw.doc/PGPcomp.htm * Synapse TCP/IP Library v.34 - by Lukas Gebauer (with source) TCP/IP library for Delphi, Kylix and FreePascal using blocking sockets. Contains simple non-visual objects for easy programming of command line utilities, visual projects, NT services, etc. New: FreePascal 1.9.4 support; Experimental Delphi 8 support; Optional support for ICONV library; New flexible FTP directory listing parser. http://synapse.ararat.cz/ * TPJDropFiles + TPJFormDropFiles v4.1 - by Peter Johnson (with source) Two components that catch files dragged and dropped from Explorer. TPJFormDropFiles provides a window that can contain other controls and catch any files dropped anywhere on it or child controls. TPJDropFiles is a non-visual component that subclasses a form to catch files that are dropped anywhere on the form. http://www.delphidabbler.com/software.php?id=dropfiles * Merkes' Tiny Hex Editor v1.5.0.10 - by Merkes Pages A free hex editor for binary files. Allows you to edit multiple files (mdi), disk sectors and virtual memory of other processes. Tiny Hex Editor is scriptable, lets you view data structures and has a plugin interface for third party extensions. http://www.mirkes.de/en/freeware/tinyhex.php Borland Product Updates ----------------------- * Public Beta: Delphi 7.1 Update - Database Supplemental This is a public beta of database runtime files that address defects introduced in the Delphi 7.1 update. http://community.borland.com/article/0,1410,32492,00.html Articles, Tips and Tricks ========================= * Interview with Danny Thorpe about Diamondback Danny Thorpe talks about the next Delphi release. http://community.borland.com/article/0,1410,32708,00.html * Interview with Corbin Dunn about the Diamondback IDE Corbin Dunn, Software Engineer, Research and Development at Borland, talks about the Delphi IDE. http://community.borland.com/article/0,1410,32719,00.html * Borland "Diamondback" Data Services over .NET Remoting Details on data remoting with the BorCon preview edition of "Diamondback", the next version of Delphi. http://community.borland.com/article/0,1410,32718,00.html * Diamondback Preview License Update A license update that does not require an NDA or Beta Agreement. http://community.borland.com/article/0,1410,32717,00.html * BDNtv: Diamondback Preview of Data Remoting Demonstrates the ease of remoting data in a heterogeneous database environment with Diamondback. Includes setting up a local DataHub for SQL Server and InterBase then making it a remote server. And, creating a client that updates tables in both databases simply by calling one method of the DataHub component. Flash http://dotnet.borland.com/bdntv/delphi/dataremoting.html * BDNtv: Diamondback Sneak Peek A sneak peek at Diamondback's new IDE features and the new Delphi language feature for enumeration. The multiple personality IDE, refactoring for both .NET and Win32, Error Insight, Help Insight, the History View and more are shown. The for .. in .. do (foreach) enumerator syntax is also revealed. Flash http://dotnet.borland.com/bdntv/delphi/diamondbacksneakpeek.html * Delphi 8 and Microsoft .NET version 1.1 Service Pack 1 Delphi 8 has trouble compiling projects after .NET 1.1 Service Pack 1 has been installed. This article explains why and offers a workaround. Also affects the BorCon Diamondback preview release. http://community.borland.com/article/0,1410,32713,00.html * Borland CEO Touts Software Process Management InfoWorld Editor-at-Large Paul Krill spoke with Dale Fuller, president and CEO of Borland, at the BorCon conference last week about Borland's tools and ALM strategies and issues such as Java vs. .Net, Web services, and outsourcing. http://www.computerworld.com.au/index.php/id;954592276;fp;16;fpid;0 * Interview: Borland Aims for Better Code Better collaboration tools are the only route to superior software, argues Borland's David Intersimone. http://www.computing.co.uk/analysis/1157073 * DB2 Web Service Engines on Linux with Kylix 3: Part 1 - by Bob Swart Demonstrates how to build a SOAP Web service engine with Kylix 3, exposing the data from DB2 UDB database tables to the outside world. www-106.ibm.com/developerworks/db2/library/techarticle/dm-0406swart/ * DB2 Web Service Engines on Linux with Kylix 3: Part 2 - by Bob Swart Demonstrates how to build the user interface for a SOAP Web service engine with Kylix 3 on Linux, exposing the data from DB2 UDB database tables to the outside world. www-106.ibm.com/developerworks/db2/library/techarticle/dm-0407swart/ * Producing Dynamic Data-Entry Forms from DB2 Tables on Linux - B. Swart Uses Kylix 3 and dbExpress to analyze DB2 UDB database tables, fields (names and types) to allow the user to select a specific table, toggle which fields are shown, and dynamically view the output in both a datagrid and individual data-aware controls. www-106.ibm.com/developerworks/db2/library/techarticle/dm-0407swart2/ * Use Delphi Code to Create/Drop DB2 UDB Database Tables - by Bob Swart Examines the design and implementation of a Delphi application you can use to create or delete / drop tables inside IBM DB2 databases. It provides several examples of sending SQL DDL to the DB2 DBMS using Delphi and the cross-platform dbExpress data access technologies. www-106.ibm.com/developerworks/db2/library/techarticle/dm-0409swart/ * Work with IBM DB2 databases and SQL in Delphi for .NET - by Bob Swart Using Delphi code to create/drop DB2 database tables, focuses on the use of SQL queries to build simple and more complex SQL SELECT queries to end up with master-detail relations. Also examines SQL joins in detail, covering examples of inner joins, left/right outer joins, and the differences between them. www-106.ibm.com/developerworks/db2/library/techarticle/dm-0409swart1/ Tutorials and Training ====================== * Free Web Seminars More than 10 on-demand Web seminars from Borland to help you optimize your software delivery. http://community.borland.com/article/0,1410,32698,00.html News ==== * Borland Delphi 2005 Boosts Microsoft Windows Productivity Borland today announced Delphi 2005, previously codenamed Diamondback. Delphi 2005 combines Win32, .NET, Delphi and C# support all within one environment, significantly advances developer and team productivity and integrates with Borland's leading ALM solutions. http://www.tmcnet.com/usubmit/2004/Oct/1081925.htm * Software Delivery Strategy Gets Under Way at Borland Kicking off its Software Delivery Optimization campaign, Borland announced upgrades to CaliberRM requirements management and StarTeam configuration management software at BorCon. Also at the conference, the company demonstrated the next version of its Delphi IDE for Windows application development. http://sdtimes.com/news/111/story7.htm * Borland Scheme Aims to Maximise Business Value of Software Work Borland aims to turn software development into a simple business process with its Software Delivery Optimisation programme, announced at the BorCon 2004 earlier this month. http://www.computerweekly.com/articles/article.asp?liArticleID=133397 * Borland Moving Forward with SDO Borland took a new direction this week, with the announcement of Software Delivery Optimization. SDO will see three technology concepts delivered around Borland's ALM tools, as the company tries to lure C-level executives and vice presidents of application development with a message that software and the business should - and can - function as one. http://www.cbronline.com/article_feature.asp? guid=E077757F-B5CD-415C-8CCC-F10E19F6CC11 * (Turn and Face the Strain) Software Changes Borland this week stood atop its soapbox preaching the evils of software projects gone awry, with projects beset by issues such as last-minute changes and differing perspectives on the potential success of development efforts. To stem the tide of botched projects, Borland pitched its Software Delivery Optimization strategy. http://weblog.infoworld.com/techwatch/archives/000712.html * Borland Adds Project-Management Features To CaliberRM Borland announced CaliberRM 2005 this week, a product designed to help software project managers take some of the guesswork out of software development. New features include tools for estimating the cost, scheduling and staffing of a project before any code gets written. http://informationweek.com/story/showArticle.jhtml?articleID=47208433 * Business Management for Software Projects End users will be able to manage software projects like a business with Borland's Software Delivery Optimisation. It aims to enable users to manage software projects like a business, according to Boz Elloy, senior vice-president of software products. http://www.computerweekly.com/articles/article.asp?liArticleID=133333 * Borland challenges Visual Studio with Diamondback With the Diamondback release of its Delphi tool for Windows applications, Borland will challenge Microsoft while accommodating .Net, Win32 and Delphi development. Michael Swindell, Borland director of product management for developer tools, said with Diamondback Borland will compete with Microsoft's Visual Studio. http://www.computerweekly.com/articles/article.asp?liArticleID=133332 * Borland Touts Software Delivery Optimization At BorCon, Borland will reveal its software delivery optimization strategy, which leverages the company's ALM and developer products to ease software development and maintenance. The strategy ultimately will feature a bundle of the company's products code-named Themis, due out in the first half of 2005, which purports to provide a platform for integrated, repeatable development processes. http://www.javaworld.com/javaworld/jw-09-2004/jw-0913-iw-borland.html * Borland Outlines Vision for Transforming Software Development Today at BorCon 2004, Dale Fuller, President and CEO of Borland, presented Borland's vision and product strategy for transforming software development from an unpredictable art form into a more manageable and repeatable business process. Borland's vision for Software Delivery Optimization builds on the technical efficiencies of ALM, and incorporates the business processes and management capabilities companies seek to ensure business-to-IT alignment, and the delivery of quality software, on time, within budget, for maximum business value. http://home.businesswire.com/portal/site/google/index.jsp? ndmViewId=news_view&newsId=20040913005322&newsLang=en * Borland and NEC Team on Online Communications Borland and NEC will partner to develop adaptor software in order to rapidly integrate web-based applications with voice and video. This will target communications over IP telephony, IP video and conferencing over online applications. http://www.cbronline.com/article_news.asp? guid=2FE9728E-9350-49C4-BC59-2C25C62987BE * Borland Acquires Software Project Planning Tool Borland has acquired of Estimate Professional, a software project planning and estimation tool from Software Productivity Center. This newly acquired tool will be embedded within the next version of the Borland CaliberRM requirements management solution. http://www.infoworld.com/article/04/08/25/HNborlestimate_1.html * Borland Joins ECMA to Help Shape Standards for the .NET Framework Borland has been elected as a member of ECMA International. As a member of ECMA, Borland will help shape standards for the .NET Framework and the C# and C++ programming languages. http://home.businesswire.com/portal/site/google/index.jsp? ndmViewId=news_view&newsId=20040812005195&newsLang=en * Borland Developer News - .NET Edition, August 2004 Your source for Delphi and C# related news. Covering mostly .NET with some Win32 development. http://community.borland.com/article/0,1410,32491,00.html ________________________________________________________________________ Irongut's Delphi Pages Dedicated to programming with Borland Delphi and Kylix. We have articles on programming, Borland and Delphi news, source code and components to use in your applications and more. >> http://www.paranoia.clara.net/ << ________________________________________________________________________ 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://news.optimax.com/delphi/links/links.exe/click?id=70C517ECAE6E http://www.programmingpages.com/?r=latiumsoftwarecomenpascal http://top100borland.com/in.php?who=20 http://top200.jazarsoft.com/delphi/rank.php3?id=latium It's just a few seconds for you that REALLY mean a lot to us. Don't forget we also need articles and there are prizes available for contributions. 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: <pascal-newsletter-owner@yahoogroups.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 the newsletter and on the Latium Software and Irongut's Delphi Pages websites. For more info contact: Dave Murray <irongut at vodafone dot net> ________________________________________________________________________ If you haven't received the full source code examples for this issue, you can get them from http://www.latiumsoftware.com/download/p0051.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 Group Home: http://groups.yahoo.com/group/pascal-newsletter/ Subscribe: pascal-newsletter-subscribe@yahoogroups.com Unsubscribe: pascal-newsletter-unsubscribe@yahoogroups.com Problems with your subscription? pascal-newsletter-owner@yahoogroups.com ________________________________________________________________________ Latium Software: http://www.latiumsoftware.com/en/index.php Irongut's Delphi Pages: http://www.paranoia.clara.net/ Copyright 2004 by Ernesto De Spirito + Dave Murray. All rights reserved. ________________________________________________________________________ |
The full source code examples of this issue are available for download.
![]() |
Errors? Omissions? Comments? Please contact us!






