Pascal Newsletter #47
The full source code examples of this issue are available for download.
![]() |
![]() |
Pascal Newsletter #47 - 25-MAY-2003 Contents 1. A few words from the editor 2. Interbase Performance Guidelines (Part II) - Interbase configuration · Regularly backup and restore · Interbase Priority Class · Turn async writes off · Turn off garbage collection · Lock hash slots · Database page size · Working set · Database cache - Development considerations · Always work with the smallest amount of data possible · Don't keep transactions open longer than needed · Large system, lots of traffic, cache your lookup tables · Program directly to the InterBase API · Use a remote connection · Fully populate and test your system during development · Prepare and parametize your queries · VCL components · Think about what you are doing · Something's will be slow · Use the client · See what your application actually does rather than what you think that it does · Use native access components · Searching for records - Other ways to improve performance · Upgrade Interbase · Read-only databases 3. Using Cabinet.dll to create your own cabinet files (.CAB) 4. Detecting right-clicks on your form's title bar How to prevent the title bar's context menu from popping up 5. High Accuracy Timings/Timer Utilizing QueryPerformanceCounter to get High Resolution Timings 6. Inline Assembler in Delphi (IX) - 128-bit integer arithmetic (3) 7. Forums / mailing lists 8. Delphi on the Net - Components, Libraries and Utilities · Shareware/Commercial · Freeware · Delphi updates - Articles, Tips and Tricks - Tutorials - Other Links - News ________________________________________________________________________ 1. A few words from the editor As usual, I have to apologize for the delay. Well, I guess you all know how it is... In the code in the article "Enumerating Network Connections" published in the last issue, the memory assigned by the call to GlobalAlloc was not freed by GlobalFree because the pointer was modified in between since it was used to iterate thru the items of the enumeration. An auxiliary pointer should be used for that purpose to preserve the value assigned by GlobalAlloc. Thanks to Wim van Nifterick for finding this out, and special thanks to Bill Boulton for helping me with Delphi 3 compatibility. Now it's time to thank the authors who contributed articles for this issue: Peter Mc Leod, Vimil Saju, James Clements, and Michael Darling, and I'm pleased to give the prizes for this issue to: * Vimil Saju (Using Cabinet.dll to create your own cabinet files) · SDL Component Suite 7.0 - by Software Development Lohninger ($99) The SDL Component Suite provides a wide range of components for science and engineering, e.g. math, statistics, chemistry, charts, data visualization, Fourier transform (FFT), 3D plots, geographic maps, curve fitting, etc. Available for Delphi 3-7 and BCB 4-6. http://www.lohninger.com/sdlindex.html * James Clements (Detecting right-clicks on your form's title bar) · NTTools 7 For Delphi - by i-tivity (US$39.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 For the next issue, we have available the following prizes for two of our contributors: * SMImport v1.75 - by Scalabium Software ($30 standard, $50 with source) Native VCL suite for importing data into a dataset without external libraries. Supports import from: Access (using DAO/MS Jet), Excel (without OLE/DDE), Lotus 123, QuattroPro, text, HTML, XML including TClientDataset format, Paradox, dBase and any TDataSet descendant. New in v1.75: visual Expression Builder; import from Word; direct import for dBase, no BDE required; load BLOB fields for XML; extended style for wizard dialog; OnCreateStructure event that allows creation of a dataset with parsed columns before real import; and more. http://www.scalabium.com/ * 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 Delphi Informant Magazine is conducting the traditional annual survey for their Readers Choice Awards. Please take a moment to select your favorite Delphi tools: http://www.delphizine.com/ballot2003/ Regards, Ernesto De Spirito eds2004 @ latiumsoftware.com __________________ Collaborated in this issue: Dave Murray and Bill Boulton ________________________________________________________________________ Vote for the Pascal Newsletter in The Programming Pages! http://www.programmingpages.com/?r=latiumsoftwarecomenpascal ________________________________________________________________________ 2. Interbase Performance Guidelines (Part II) By Peter Mc Leod <PeterMcLeod@practical.com.au> Interbase configuration ======================= Regularly backup and restore ---------------------------- Your database is a source of competitive advantage to your customers because of the information that it contains. Performing regular backups is essential to ensure the integrity of data for your clients. A restore is just as important as it optimizes the database by: - rebuild indices, - eliminate obsolete record versions (garbage collection), - defragment database pages, - rewrite database tables contiguously, and - recalculates database statistics. A good tool for performing backups and restores is IBBackup which is available from www.ibphoenix.com Note: It is suggested that before restoring your database that you make a copy of the original, and then perform your restore. This is since the Restore does Integrity checking of your database, as this is processor intensive. Essentially this means that it could be possible to have a faulty backup that cant be restored. The backup does not do this because the idea of backing up is to secure your data without impacting on system performance. Interbase Priority Class ------------------------ The Interbase Priority Class should be set to high (SuperServer version under Windows) to ensure that Interbase can demand more of the system's resources. This can be done through IBConsole in the Windows version. Or edit the ibconfig file and set the SERVER_PRIORITY_CLASS to two to achieve this (remove the # to uncomment this line otherwise the default will apply). Turn async writes off --------------------- Under Windows NT, Interbase defaults to having forced writes on. This means that write operations to Interbase, go direct to the database and not through the Operating System Cache, which is slow. On Linux systems the reverse occurs. This can result in a performance difference of more than 300% for some operations. The problem is that if you turn Async Writes off under Windows, and the Operating system crashes while Interbase is writing to disk, you run the risk of losing data, and potentially corrupting your database. As Linux is inherently more stable this is not so much of a risk. If you wish to turn Async writes off then make sure that you make lots of backups of your database and that you have a good UPS on your server (you should do lots of backups and have a good UPS anyway): GFIX -WRITE ASYNC/SYNC MYDATABASE.GDB Turn off garbage collection --------------------------- Interbase by default performs a sweep of the database to Garbage collect old records when too many accumulate. This unfortunately can severely impact on the performance of the client process that caused this threshold to be reached. To disable automatic Garbage collection, you issue the following command from Gfix to your database: gfix -h 0 Note: Regular Backup and Restores will perform Garbage collection on the Database. This is another reason why the database should be backed up regularly and restored as often as is practical. Lock hash slots --------------- The Lock hash slots parameter is used to determine the size of the hash table utilized to find locks on a particular database object (this is true of all systems except VAX/VMS). The number should be a prime number to help the hash algorithm produce a good distribution. Usually the first indication that a problem exists with the size of the Lock Hash Slots configuration is declining performance for the Interbase Server (where you have lots of users and a large cache pages). To determine if this is the problem produce a Lock table print out (while the system is actively being used) and examine the average hash length. If this is greater than 10 you have a problem. To calculate a new Lock Hash Slot parameter multiply the average length by the current number of slots and divide the result by nine. Adjust this up as necessary to ensure that it is a prime number, but one that is between 101 and 2048 (these are the limits for this parameter). To change the parameter edit the ibconfig file and change the value, but remember to remove the '#' from LOCK_HASH_SLOTS so this setting will take effect. I initially set the LOCK_HASH_SLOTS to 501 for most Interbase installations that we use. If you perform this on the Super Server Architecture you should increase the lock table size as well. Database page size ------------------ The Database page size determines how much data will be retrieved with one logical access to the database. Interbase has a default 1Kb page size, with permitted values being 2Kb, 4Kb, and 8Kb. For small Databases (less than 4 Gig in size), set the Database Page size to 4096 (4K) bytes, for large databases this should be set to 8192 (8K). Tests on database performance indicate that a change from a 1Kb page size to a 4Kb page size can increase database performance around 20%. By having a 4Kb, page size for most databases, the database I/O matches the operating system I/O default sizes, resulting in greater efficiency and performance. Other advantages of a large page size include: · Less record fragmentation as more records can be stored on a page · Fewer pages returned for a given query (as records are stored more contiguously) · Index B-trees are shallower · I/O is more contiguous The above Database Page sizes are guidelines only; it is recommended that you perform some testing, to determine what size is most applicable to your system. For a change in the database page size to take effect you will need to perform a backup and restore of your database. Working set ----------- The working set configuration parameters are only applicable to Interbase running under Windows (using the Super Server architecture). These configuration parameters determine how much RAM is dedicated to the Interbase process. The minimum Process working set defines the minimum amount of physical RAM that is guaranteed for the Interbase process. The maximum working set defines the amount of memory above which Interbase will start to use the system cache. I recommend that the minimum working set is determined by taking the allocation for the Database Cache Pages and adding three megabytes. Leaving the maximum Process working set to zero will allow the system to determine the point at which Interbase needs to swap to disk. The maximum working set should always be higher (or set to zero) than the Database Cache otherwise the system will continuously page to disk for all operations. Database cache -------------- The Database Cache is a Cache of the number of pages of the database that are cached by the Server's RAM. Some experimentation with setting the database Cache (in ibconfig) to a value between 256 and 10,000 produces increased performance up to a point. After this point declining performance is noticed. It is also a good idea to set the cache for the database using GFIX with the following command: Gfix -buffers 10000 -user sysdba -password masterkey mydatabase.gdb If you have a small database then you should use statistics to find out how many pages are in the database. You shouldn't set the Cache on the database to a figure higher than the number of pages in the database, since any given page from disk will only occupy one page in the cache. Development considerations ========================== Always work with the smallest amount of data possible ----------------------------------------------------- Network traffic is a major factor in the perceived performance of your application. If you have 100,000 records and you do something like "Select * from myTable" you will be pulling down all the records. Using filters to only return a subset of data helps reduce this. If possible avoid the use of grids that display a large set of records. Use SQLMonitor (or it's equivalent) to profile your SQL commands and see what ACTUALLY happens as your application runs. Don't keep transactions open longer than needed ----------------------------------------------- Holding a transaction open can lock records in a database. Holding transactions open for a long period of time will also increase the amount of memory that Interbase requires to keep track of those transactions. Instead of starting a transaction as soon as a data input screen is opened and then committing the transaction when the user presses Save, it is better to get a copy of the data and then start a transaction and commit the transaction as soon as the Save button is pressed. A number of techniques facilitate this approach, such as ClientDatasets. These techniques have the advantages of: · Reducing network traffic. · Reduces the risk of database locks · Reduces the life of a transaction · Reducing the amount of memory that Interbase requires keeping track of those transactions Large system, lots of traffic, cache your lookup tables ------------------------------------------------------- If you have any data that does not change (such as States, or Countries), then you have an opportunity to cache this information in a ClientDataset on the client machine (rather than retrieve the details from the Server), then you can simulate a join on the client side by using a calculated field. This allows you to reduce the number of fetches that you need to do to the database, and reduces your network traffic. Program directly to the InterBase API ------------------------------------- If speed is an absolute necessity then a program written in C with embedded SQL performs better than an Interbase client application running through layers of middleware (such as the BDE etc). This type of application is programmed directly to the API in GDS32.DLL, which produces its speed improvement. Use a remote connection ----------------------- When developing your application do not use the local connection string when connecting to your database (c:\path\mydatabase.gdb), as it uses memory-mapped files to communicate to your database. With some versions of Interbase the use of local and remote connection strings together could cause a physical corruption of the database. Use a remote connection string, as this will give a better indication of your system's actual performance (servername:c:\path\mydatabase.gdb) and will allow you to pinpoint problems early on. Better still, actually develop your application by connecting to a database on another machine across a network. Fully populate and test your system during development ------------------------------------------------------ Often developers will use a cut down system during the development and testing process on their development machine. The disadvantage of this is that retrieving only a few records (or even a few hundred records) locally will be extremely fast. The reality is that you are most likely going to be developing a client-server system which has to run across a network, and may have many thousands or even millions of transactions in your system. To test your system, run it across a network, ensuring that the database is properly populated (and I would recommend populating it with around 1/3 more records than you would expect that someone would have in their system). Preferably perform your tests on the minimum hardware and network environment that you would expect your system to run on. Prepare and parametize your queries ----------------------------------- Wherever possible, write a query statement which can be parameterized and prepare the query before executing it (it only needs to be prepared once as it stays prepared until you explicitly unprepare it or you change the contents of the SQL property). Prepared and parameterized queries/statements are faster than non-prepared parameterized queries/statements. VCL components -------------- A TQuery component was designed for use in client-server applications, and should always be used in replace of a TTable component which is for local database development. When using TQuery, allow the server to handle updates, deletes and conflicts by having RequestLive=False. Don't use Locate or RecordCount as these perform a fetchall. Use a where clause to ensure that the server does the filtering of data for you. Think about what you are doing ------------------------------ When designing your system remember just because Interbase let's you do something that does not mean to say that it is a good idea. All actions have a consequence. Think about how you are designing and developing your system and what the ramifications are going to be for you, the network and the clients. Remember it is possible that someone else will have to maintain this system. Some things will be slow ------------------------ When developing a system if you have to perform the same task over and over again, say a million times, it is going to be slow regardless of how fast your client and server are. If this is the case see if your design philosophy can allow you to design this type of processing out of the system. In some cases this is not going to be possible, in which cases you may need to employ a system where this sort of processing is performed outside of normal client usage. Use the client -------------- In a client-server system, you don't have to send everything back to the server for processing. You can distribute the load by performing some of your work on the client machine. If you cache the details of your calculations then the advantage of this is reduced network traffic, shorter transactions and not bogging the server down with every single process. An example of this would be calculating the cost for each item on a purchase order and the total for the purchase order on the client. See what your application actually does rather than what you think that it does --------------------------------------- Tools such as SQL Monitor give you an insight into the way your application requests data from Interbase. These tools are invaluable as they allow you to see things like: · Connect/Disconnect · Transactions · Execute Statements · Statement Operations Also various VCL components behave in different ways. Using SQL Monitor gives you the opportunity to investigate what is going on behind the scenes with these components, and also what happens when you make design changes to your application. Other tools, which should be in your application development arsenal, include: · Interbase Performance Monitor by Craig Stuntz (requires Interbase 7.0 or higher) · Interbase Plan Analyser by Craig Stuntz · Sleuth QA Suite by TurboPower Software (allows you to performance tune your Delphi/C++ Builder application) Use native access components ---------------------------- The BDE is now a deprecated system and will no longer be supported by Borland. Components like IBX, FibPlus, and IBObjects provide a performance increase by around 40%, in comparison to the BDE. These components also provide access to more of Interbase's internal features. The use of such components however does tie you to the Interbase platform. If this is a problem then the dbExpress components, provide you with the ability to connect to Interbase and other databases, while still obtaining good performance (not quite as good as IBX etc, but certainly no where near as slow as the BDE). Searching for records --------------------- Soundex is a method of indexing that was developed by the U.S. Census department, for grouping similar sounding names together. As an example, performing a search of 300,000 records for the name "smith" could take around 2.95 to complete, whereas a soundex could yield the result in around 0.77 seconds, except it would include the name "smith" and names that sound like "smith". For a good overview on creating and using a Soundex function refer to the article "Implementing a Soundex Function" by John Midwinter found at http://www.ibphoenix.com Other ways to improve performance ================================= Upgrade Interbase ----------------- Each new version of Interbase (or Firebird) implements enhancements that increase the performance of the RDBMS, or increases programmer flexibility through language extensions. The increased performance and functionality allows you to build a better client-server system. Due to the recent enhancements to these products anyone using a version of Interbase prior to version 7.0 should consider upgrading. If this is not an option, then consider upgrading to the latest version of Firebird. Read-only databases ------------------- A database will normally leave some free space on it's pages (about 25% is left free) to allow for new record versions. In a database where the primary purpose for retrieving and viewing data, this means more pages need to retrieved to view the data. For these read only databases these pages can be filled up so that the data is more contiguous and less pages need to be retrieved by using the following GBAK command: GBAK -C -USE_ALL_SPACE backup.gbk mydatabase.gdb ________________________________________________________________________ Delphi BUGS? Catch & Log every BUG showing Unit, Class, Method, Line #. Now with support for command-line compiler and IntraWeb applications. http://www.eurekalog.com/bannerclick.php?id=15 ________________________________________________________________________ 3. Using Cabinet.dll to create your own cabinet files (.CAB) By Vimil Saju vimil@mec.ac.in I have created a component that enables one to compress files to a cabinet file. This component requires the cabinet.dll which usually resides in your system folder. This component consists of two units. The first unit contains all the structures required by the component. I have updated the Cabinet unit. Now you can add files by using wild cards. The Compression now takes place in a separate thread, so that your program won't freeze. I have fixed the bug in OnStatusEvent, it shows the progress correctly now. I have also added an abort function which can be called during the compression process so to cancel compression. You can now specify the directory in which you want to decompresss the file using the 'AddFile' function. I have added a decompress facility, though it is not yet perfected. The Decompressor and compressor run in separate threads so that the application does not freeze. You can also get the list of files present in a cabinet without extracting them. Many bugs were removed. Now there are two components: TCabCompressor and TCabDecompressor. To select an individual file to decompress you have to first select it by calling the funtion CabDecompressor1.Files[0].Select. To select all files you can call the function CabDecompressor1.SelectAllFiles and to select files using wildcards use the function CabDecompressor1.SelectFilesByWildCard. The BeforeCopyFile event in TCabDecompressor Class has been updated to include a parameter called Overwrite which indicates whether the file being decompressed will overwrite an existing file or not. The two units along with a demo program are attached in the zip archive. __________________ The latest version of this article and its source code can be found at Delphi3000.com: http://www.delphi3000.com/articles/article_1820.asp ________________________________________________________________________ TsiLang Components Suite, by SiComponents. A full set of professional components for building elegant, useful and user friendly multilingual applications in a snap. http://www.sicomponents.com/tsilang1.html ________________________________________________________________________ 4. Detecting right-clicks on your form's title bar How to prevent the title bar's context menu from popping up By James Clements <essexboy @ bigfoot.com> How do I detect a right click and/or kill the menu for my title bar? This is a relatively simple problem. You just need to know the correct Windows message to trap. Here's how to do it: Declaration: procedure WMNCRButtonDown(var Msg : TWMNCRButtonDown); message WM_NCRBUTTONDOWN; Definition: procedure TMainFrm.WMNCRButtonDown(var Msg : TWMNCRButtonDown); begin if (Msg.HitTest = htCaption) then begin // your code here // the next line kills the menu Msg.HitTest := 0; end else inherited; end; Additional information: * NC stands for non-client * WMNCLButtonDown or WMNCMButtonDown may be used instead for left or middle button respectively * No WM_NCRBUTTONUP message is generated, only a WM_RBUTTONUP when the mouse button is released This has been tested with Delphi 5 on Windows 2000, 95, 98 and NT 4.0. It should also work fine with other versions of Delphi, but these have not been tested. ________________________________________________________________________ Resource Builder 2.0, by SiComponents. A full-featured tool for visually building RC scripts and resource files for your apps. Includes powerful image editors and JPEG support. http://www.sicomponents.com/rbldr.html ________________________________________________________________________ 5. High Accuracy Timings/Timer Utilizing QueryPerformanceCounter to get High Resolution Timings By Michael Darling <michael.darling @ which.net> The standard Time and Now functions, and even the TTimer, are only accurate to 55 milliseconds as they use the PC's clock timer. For higher accuracy timings, Windows provides a high performance counter which is accessed through QueryPerformanceCounter and QueryPerformanceFrequency. This class implements a Delphi interface to these methods. The attached unit implements a HighResTimer object to simplify use of the WinAPI QueryPerformanceCounter and QueryPerformanceFrequency high- resolution counter functions. This can then be extended to provide WriteToFile, LogToDB functionality, etc. Just add the unit to your uses clause and then create an instance of THighResTimer whenever you need it. Note: The unit contains IFDEFs to handle the change to TLargeInteger in Delphi versions 3, 4 & 5+. Once created, the HighResTimer just needs to be started before performing an action then stopped once the actions been performed. The time taken can be retrieved as a TDateTime by calling the Time property or as an integer by calling the Ticks property. Example: var MyHighResTimer: THighResTimer; i, j: Integer; begin MyHighResTimer := THighResTimer.Create; try MyHighResTimer.Start; for i := 0 to 1000 do begin j := i; end; MyHighResTimer.Stop; ShowMessage(Format('Operation took'#13'Time: %8.8f'#13'Ticks:%d', [MyHighResTimer.Time, MyHighResTimer.Ticks])); finally MyHighResTimer.Free; end; end; ________________________________________________________________________ * LMD StoragePack - by LMD Innovative - Shareware (EUR 59) Eight components for saving/restoring of configuration data (e.g. at design time, via extended Property Selection dialog) to/from the Windows Eegistry or Ini-, XML- and binary files, being easy to switch between these formats. Full source code and demo projects included. http://www.ceberus.com/lmd/products/index.php3#P9 ________________________________________________________________________ 6. Inline Assembler in Delphi (IX) - 128-bit integer arithmetic (Part 3) By Ernesto De Spirito <eds2004 @ latiumsoftware.com> In this third and last part of the series on 128-bit integers (that we called huge integers, big integers or large integers) we'll finally get to see the actual arithmetics, with the four fundamental operations (addition, subtraction, multiplication and division). Before getting into them I'd like to say that the procedures and functions introduced in the preceeding two parts have been corrected and also further optimized. I still haven't been able to test them as much as I'd have liked to. If you find any bugs or have any comments about the source code, please drop me an email. Addition ======== How do we add two numbers, each made up of four 32-bit integers? Well, it's actually pretty easy. We simply add them in the same way that we would add two numbers of four decimal digits (like 3597 and 0015 for instance), except that here each "digit" can have about 4 billion different (2^32) values instead of just ten. The algorithm would be like this: function AddWithCarry(x: Longint; y: Longint; var Carry: Boolean): Longint; forward; function HugeAdd(x: Hugeint; y: Hugeint): Hugeint; // Result := x + y; var Carry: Boolean; begin Carry := False; Result[0] := AddWithCarry(x[0], y[0], Carry); Result[1] := AddWithCarry(x[1], y[1], Carry); Result[2] := AddWithCarry(x[2], y[2], Carry); Result[3] := AddWithCarry(x[3], y[3], Carry); end; AddWithCarry is a fictitious function which returns an integer with the low order 32 bits of the result of the addition of the two arguments, plus 1 if Carry (the third argument) is True. It also stores True or False to the Carry (passed by reference) depending on whether the addition generated a carry or not (or whether the carry is 1 or 0, if you want to see it that way). Actually, this function doesn't have to be fictitious: function AddWithCarry(x: Longint; y: Longint; var Carry: Boolean): integer; asm // if Carry then CF := 1 else CF := 0; test byte ptr [ecx], -1 // Side-effect: CF := 0; jz @@NoCarry stc // CF := 1; @@NoCarry: // Result := x + y + CF; CF := GeneratedCarry; adc eax, edx // Carry := CF; setc byte ptr [ecx] end; It would be more efficient to have HugeAdd coded entirely in assembler: function HugeAdd(x: Hugeint; y: Hugeint): Hugeint; // Result := x + y; // Parameters: EAX = @x; EDX = @y; ECX = @Result asm push esi mov esi, [eax+_0_] // ESI := x[0]; add esi, [edx+_0_] // ESI := ESI + y[0]; mov [ecx+_0_], esi // Result[0] := ESI; mov esi, [eax+_1_] // ESI := x[1]; adc esi, [edx+_1_] // ESI := ESI + y[1] + Carry; mov [ecx+_1_], esi // Result[1] := ESI; mov esi, [eax+_2_] // ESI := x[2]; adc esi, [edx+_2_] // ESI := ESI + y[2] + Carry; mov [ecx+_2_], esi // Result[2] := ESI; mov esi, [eax+_3_] // ESI := x[3]; adc esi, [edx+_3_] // ESI := ESI + y[3] + Carry; mov [ecx+_3_], esi // Result[3] := ESI; pop esi end; Subtraction =========== Subtraction works very much like addition, but instead of generating a carry, the operation generates a borrow (also represented by the Carry Flag) if the minuend (first operand) is less than the subtrahend (second operand): function SubtractWithBorrow(x: Longint; y: Longint; var Borrow: Boolean): Longint; forward; function HugeSub(x: Hugeint; y: Hugeint): Hugeint; // Result := x - y; var Borrow: Boolean; begin Borrow := False; Result[0] := SubtractWithBorrow(x[0], y[0], Borrow); Result[1] := SubtractWithBorrow(x[1], y[1], Borrow); Result[2] := SubtractWithBorrow(x[2], y[2], Borrow); Result[3] := SubtractWithBorrow(x[3], y[3], Borrow); end; function SubtractWithBorrow(x: Longint; y: Longint; var Borrow: Boolean): Longint; asm // if Borrow then CF := 1 else CF := 0; test byte ptr [ecx], -1 // Side-effect: CF := 0; jz @@NoBorrow stc // CF := 1; @@NoBorrow: // Result := x - y - CF; CF := NeededBorrow; sbb eax, edx // Borrow := CF; setc byte ptr [ecx] end; You should be ready to write a pure assembler version of HugeSub, since it's the same as HugeAdd, but all you have to do is replace ADD and ADC with SUB and SBB respectively. Opposite number =============== Given a number, these implementations of HugeNeg return it's opposite number (two's complement): function HugeNeg(x: Hugeint): Hugeint; begin // Result := (Not x) + 1; Result := HugeAdd(HugeNot(x), IntToHuge(1)); end; function HugeNeg(x: Hugeint): Hugeint; begin // Result := 0 - x; Result := HugeSub(IntToHuge(0), x); end; The second one is the simplest and fastest because it involves a single operation, and now that we know how to subtract, we can implement it in assembler: function HugeNeg(x: Hugeint): Hugeint; // Result := -x; // Parameters: EAX = @x; EDX = @Result asm // Result := 0 - x; push esi xor esi, esi mov ecx, [eax+_0_] // x[0] sub esi, ecx // 0 - x[0] mov ecx, 0 mov [edx+_0_], esi // Result[0] mov esi, [eax+_1_] // x[1] sbb ecx, esi // 0 - x[1] - Borrow mov esi, 0 mov [edx+_1_], ecx // Result[1] mov ecx, [eax+_2_] // x[2] sbb esi, ecx // 0 - x[2] - Borrow mov ecx, 0 mov [edx+_2_], esi // Result[2] mov esi, [eax+_3_] // x[3] sbb ecx, esi // 0 - x[3] - Borrow mov [edx+_3_], ecx // Result[3] pop esi end; Multiplication ============== A way of multiplying numbers is by means of an addition loop: function HugeMul(x: Hugeint; y: Hugeint): Hugeint; begin SetZero(Result); while not HugeIsZero(y) do begin Result := HugeAdd(Result, x); HugeSub(y, 1) end; end; Computationally speaking, this algorithm is quite poor. For example, if the value of "y" was 4 million, the loop would repeat 4 million times! Anyway, the idea would still good if we could somehow accelerate the process. Let's play a little bit with algebra: x * y = x * (y[3]*2^96 + y[2]*2^64 + y[1]*2^32 + y[0]*2^0) = (x*y[3])*2^96 + (x*y[2])*2^64 + (x*y[1])*2^32 + (x*y[0])*2^0 Now we have reduced the problem of multiplying two Hugeint numbers to multiplying a Hugeint number by a 32-bit integer. We multiply the first operand by the four integers that make up the second operand and then we shift the partial results by 0, 32, 64, and 96 bits (to multiply them by 2^0, 2^32, 2^64 and 2^96), and finally we add these values to get the final result. function HugeMulInt(x: Hugeint; y: Longint): Hugeint; forward; function HugeMul(x: Hugeint; y: Hugeint): Hugeint; begin Result := HugeShl(HugeMulInt(x, y[3]), 96) + HugeShl(HugeMulInt(x, y[2]), 64) + HugeShl(HugeMulInt(x, y[1]), 32) + HugeMulInt(x, y[0]); end; This is exactly the way we multiply decimal numbers when performing caculations on a paper, except that here the base is 2^32 instead of ten. Let's see now how we can a multiply a Hugeint by an integer: function MultiplyWithCarry(x: Longint; y: Longint; var Carry: Longint): Longint; forward; function HugeMulInt(x: Hugeint; y: Longint): Hugeint; // Result := x * y; var Carry: Longint; begin Carry := 0; Result[0] := MultiplyWithCarry(x[0], y, Carry); Result[1] := MultiplyWithCarry(x[1], y, Carry); Result[2] := MultiplyWithCarry(x[2], y, Carry); Result[3] := MultiplyWithCarry(x[3], y, Carry); end; function MultiplyWithCarry(x: Longint; y: Longint; var Carry: Longint): integer; // Result := LoDWord(x * y + Carry); // Carry := HiDWord(x * y + Carry); asm // EDX:EAX := EAX * EDX; // x * y mul edx // Inc(EDX:EAX, Carry); add eax, [ecx] adc edx, 0 // Carry := EDX; // High order 32 bits of the result mov [ecx], edx; end; MultiplyWithCarry is very much like AddWithCarry, but it performs a multiplication instead of an addition, and it generates a carry of 32 bits instead of just one bit (the multiplication of two 32-bit values generates a 64-bit result, while the addition of two 32-bit values can generate a 33-bit result). MultiplyWithCarry first performs an unsigned multiplication of "x" (EAX) by "y" (EDX), using the MUL opcode. The result is a 64-bit unsigned integer in EDX:EAX, to which the function adds the Carry passed by parameter. The function returns the lower 32 bits of this final result (located EAX), and the higher 32 bits (EDX) constitute the carry for the next multiplication, which are stored in the Carry parameter (passed by reference). An assembler implementation of HugeMul and HugeMulInt can be found in the source code attached. For reasons of simplicity, in the examples above the functions consider the numbers are unsigned, but the assembler implementations consider signed numbers. Also, the attached version of HugeMul doesn't call HugeMulInt or HugeShl, and is highly optimized. Instead of considering a Huge integer as four 32-bit integers multiplied by four powers of 2^32, we consider them as 128 1-bit integers multiplied by 128 powers of 2: bit127 * 2^127 + bit126 * 2^126 + ... + bit1 * 2^1 + bit0 * 2^0 Since each bit can only be 0 or 1, the algorithm shown above can be greatly simplified: function HugeMul(x: Hugeint; y: Hugeint): Hugeint; // Result := x * y; var i: Longint; begin SetZero(Result); for i := 0 to 127 do if BitTest(y, i) then Result := HugeAdd(Result, HugeShl(x, i)); end; The idea is to add different powers of 2 of "x", depending those powers on the bits set on "y". For example, if "y" was 20, bits 5 and 3 would be on (20 in decimal is 10100 in binary), so only two additions would be performed, and the result would be HugeShl(x, 3) plus HugeShl(x, 5). This algorithm can be coded quite efficiently in assembler, but still the first algorithm will work faster. The reason why I've shown this is because it'll make it easier to understand the algorithm we'll use for divisions. Division ======== Let's first see the case of a division of a Hugeint by a 32-bit integer, which should be easy to understand: function DivideWithRemainder(x: Longint; y: Longint; var Remainder: Longint): Longint; forward; function HugeDivInt(x: Hugeint; y: Longint): Hugeint; // Result := x div y; var Remainder: Longint; begin Remainder := 0; Result[0] := DivideWithRemainder(x[3], y, Remainder); Result[1] := DivideWithRemainder(x[2], y, Remainder); Result[2] := DivideWithRemainder(x[1], y, Remainder); Result[3] := DivideWithRemainder(x[0], y, Remainder); asm mov edx, Remainder end; end; function DivideWithRemainder(x: Longint; y: Longint; var Remainder: Longint): Longint; // Result := Remainder:x div y; // Remainder := Remainder:x mod y; asm push esi mov esi, edx // y mov edx, [ecx] // Remainder // EAX := EDX:EAX div ESI; // EDX := EDX:EAX mod ESI; div esi // Remainder := EDX; mov [ecx], edx; pop esi end; HugeDivInt leaves the remainder of the division in EDX, so it can be used in a function returning the remainder of the division: function HugeModInt(dividend: Hugeint; divisor: Longint): Longint; // Result := dividend mod divisor; // Parameters: EAX = @dividend; EDX = @divisor; asm sub esp, TYPE(Hugeint) // Make place on the stack for a Hugeint mov ecx, esp // to hold the result of the division call HugeDivInt // Perform the division add esp, TYPE(Hugeint) // Restore the stack pointer mov eax, edx // Result := Remainder; // was left in EDX end; For the case of two huge integers we can think of an algorithm like the one we would use to divide two numbers of four digits with paper and pencil, but it turns to be quite complex, plus it isn't actually very fast since it implies divisions, multiplications, and substractions, and sometimes you take one step forwards and two steps back. Is there another possible algorithm? Yes, there is: function HugeDiv(dividend: Hugeint; divisor: Hugeint): Hugeint; // Result := dividend div divisor; begin if HugeIsZero(divisor) then raise EDivByZero.CreateRes(@sDivByZero); Result := 0; while HugeCmp(dividend, divisor) >= 0 do begin dividend := HugeSub(dividend, divisor); Result := HugeAdd(Result, IntToHuge(1)); end; end; Of course, this algorithm turns out to be awfully slow (if we divide 12 million by 3, the loop would execute 4 million times), but we can speed things up if we subtract from the dividend the divisor multiplied by different powers of 2, from higher to lower, setting the corresponding bit of the result every time we perform a subtraction (the bit in the position of the power of 2 that was used). It's the inverse of what we did in the case of a multiplication shown above. The division process would then be reduced to just 128 subtractions at most. In the following example, the dividend is 20 (10100 in binary) and the divider is 3 (11 in binary): 10100 - 11 * 2^2 = 10100 - 1100 = 1000 Result := 100 1000 - 11 * 2^1 = 1000 - 110 = 10 Result := 110 Initially, 11 * 2^2 is the highest value that is less or equal to the dividend, so we subtract that value from the dividend and we set bit 2 of the result because we subtracted the divisor multiplied by two to the power of 2. So far, the remainder is 8 (1000 in binary), and 11 * 2^1 is the highest value that is less than or equal to this remainder, so we subtract that value from the remainder, and we set bit 1 of the result because we subtracted the divisor multiplied by two to the power of 1. The remainder is 2 (10 in binary), and since the divisor is greater than that value, division stops there. The remainder of the operation would then be 2 (10 in binary) and since bits 2 and 1 of the result were set, the result is 110 in binary, i.e. 6 in decimal. function HugeDiv(dividend: Hugeint; divisor: Hugeint): Hugeint; var _r_: Hugeint; // remainder _d_: Hugeint; // divisor _q_: Hugeint; // quotient BitPosR, BitPosD, count: integer; begin _r_ := dividend; _d_ := divisor; HugeSetZero(_q_); BitPosD := HugeBitScanReverse(_d_); if BitPosD = -1 then RaiseDivByZero; BitPosR := HugeBitScanReverse(_r_); count := BitPosD - BitPosR; if count > 0 then _d_ := HugeShl(_d_, count); repeat if HugeCmp(_d_, _r_) <= 0 then begin _r_ := HugeSub(_r_, _d_); HugeBitSet(_q_, count); end; _d_ := HugeShr(_d_, 1); dec(count); until count < 0; Result := _q_; asm lea edx, _r_ end; end; HugeBitScanReverse is a function that returns the position of the first non-zero bit, performing the search from bit 127 to bit 0. If all bits are zero, the result is -1. We use HugeBitScanReverse to determine the first power of two we should multiply the divisor in order to begin the iteration. The assembler implementation of HugeDiv that you can find attached supports signed numbers. It is just a first approximation, and it can be heavily optimized. The function leaves in EDX the address of the remainder, so it can be used by a function returning the modulus of the division: function HugeMod(dividend: Hugeint; divisor: Hugeint): Hugeint; // Result := dividend Mod divisor; // Parameters: EAX = @dividend; EDX = @divisor; ECX = @Result asm push ecx // @Result call HugeDiv // EDX := @remainder; pop eax // EAX := @Result; call HugeMov // EAX^ := EDX^; end; ________________________________________________________________________ Vote for the Pascal Newsletter in The Top 100 Programming Sites! http://www.sandbrooksoftware.com/cgi-bin/TopSite2/rankem.cgi?id=latium ________________________________________________________________________ 7. 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: 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 :-) http://groups.yahoo.com/group/delphi-en/ Subscription: http://groups.yahoo.com/group/delphi-en/join delphi-en-subscribe@yahoogroups.com * 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/ ________________________________________________________________________ 8. Delphi on the Net By Dave Murray <irongut @ vodafone.net> Components, Libraries and Utilities =================================== Shareware/Commercial -------------------- * SMImport v1.75 - by Scalabium Software ($30 standard, $50 with source) Native VCL suite for importing data into a dataset without external libraries. Supports import from: Access (using DAO/MS Jet), Excel (without OLE/DDE), Lotus 123, QuattroPro, text, HTML, XML including TClientDataset format, Paradox, dBase and any TDataSet descendant. New in v1.75: visual Expression Builder; import from Word; direct import for dBase, no BDE required; load BLOB fields for XML; extended style for wizard dialog; OnCreateStructure event that allows creation of a dataset with parsed columns before real import; and more. http://www.scalabium.com/ * 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/ * Storage Library v3.24 - by DeepSoftware.Ru ($39) Storage Library - elegant way for application settings management. Supports working with ini files, registry, xml files, TStream objects. Provides encryption, unicode support, working with published properties without programming, saving form position and much more... http://www.deepsoftware.ru/rsllib/index.html * Delphi Knowledge Base v1.5 ($29) A unique collection of Delphi tips and articles where Delphi programmers can find ideas, solutions and share their experience. The new version contains these new features: fast article search, integrated flat type interface, added bookmark system, new filtering, grouping and sorting features in the article grid, multilingual interface, generally improved article update tool and much more... http://www.baltsoft.com/product_dkb.htm Freeware -------- * IBUtils v0.9.2.4 - by Ales Kahanek IBUtils is designed to simplify database design for Interbase and Firebird databases by showing the links between the tables in your database visually, like some CASE tools do. It does not allow database editing, it is a read-only tool. The model is saved to INI-like files or can be exported as an image to a JPG or BMP file. Uses IBObjects. http://www.alikiwi.com/ibutils/ibutils.htm * Key Objects Library v1.72 - by Delphree (with source) Based on experience aquired on eXtreme Class Library project. Main purpose is to create smaller programs using Delphi environment. http://delphree.clexpert.com/pages/app_KOL.htm * GPU 0.788b - by Delphree (with source) GPU is a Gnutella client for sharing files and CPU-resources. The objective is to develop a robust framework for distributed computing on a peer-to-peer grid. http://delphree.clexpert.com/pages/app_GPU.htm * TurboPower SysTools for Kylix v1.01 - by TurboPower (source) (KYLIX) A library of utility routines and algorithms for Borland Kylix. Among other things, it supports 1-Dimensional bar codes, date time and string routines, sorting, a regular expression engine and a run-time math expression analyzer. https://sourceforge.net/projects/tpsystoolskylix/ Delphi Updates -------------- * Patch: glibc update for Kylix 3 C++ package loading - by John Kaster Linux distributions using glibc 2.2.x will probably encounter issues loading the database and SOAP packages for the Kylix 3 IDE for C++. This patch resolves that issue. http://community.borland.com/article/0,1410,29968,00.html Articles, Tips and Tricks ========================= * Sip from the Firehose: It all starts with Define! - by David I In the recent BDN 2003 Survey, David I asked members a question about what drives their development processes and decisions. In this article he reports the results. http://community.borland.com/article/0,1410,30043,00.html * Interview with Jeff Duntemann - by Clay Shannon Jeff Duntemann tells about his experiences working for Borland, writing and editing for Coriolis and Visual Developer, a rigged programming contest he participated in vs. Bill Gates, what he does everywhere, and what he's been up to lately. http://community.borland.com/article/0,1410,30012,00.html * Interview with Steve Teixeira - by Clay Shannon Interview with Steve Teixeira, co-author of the classic "Delphi X Developer's Guide". Among other things, Steve tells about his days at Borland, how the above tome came about, and "geek" practical jokes. http://community.borland.com/article/0,1410,29925,00.html * Using Semaphores in Delphi Part 2: The Connection Pool - Cary Jensen Semaphores are used to coordinate multiple threads and processes. The ability of semaphore to provide multiple threads with simultaneous access to a shared resource is highlighted by the TFixedConnectionPool class described in this article. http://community.borland.com/delphi/0,1419,1,00.html * Binary Serialization with the .NET Framework and Delphi for .NET - by Marcel van Brakel This article explains binary serialization, complete with Delphi for .NET and C# source code. http://community.borland.com/article/0,1410,29787,00.html * Simple Programming Tip #1 - by Charlie Calvert This article describes the first of several simple programming tips. The discussion and code in this article is generic and applies equally to C++, C#, Delphi or Java. The tip for this article is: Avoid writing code that does anything substantial inside a visual container, instead write code inside separate classes designed for a single purpose. http://community.borland.com/article/0,1410,30011,00.html * MessageBox on top of "stay on top" forms - by Zarko Gajic This tip causes "stay on top" forms to allow a MessageBox to appear on top. After the message box is closed, the topmost forms are restored so that they continue to float to the top. http://delphi.about.com/cs/adptips2003/index.htm * Mouse moving the contents of a ScrollBox - by Zarko Gajic How to move a TImage object in a ScrollBox with the mouse, like a drag and drop operation - without the scroll bars. http://delphi.about.com/library/weekly/aa050603a.htm * Sorting records in Delphi DBGrid - by Zarko Gajic How to sort records in Delphi DbGrid by clicking on the column title. How to change the appearance of the selected column title to reflect the sort order. How to change the cursor when moving over the DBGrid column titles. http://delphi.about.com/library/weekly/aa042203a.htm * Choosing a ZIP Library for Delphi - by Mark Steinberg Describes the pros and cons of several ZIP libraries - VCLZip, ZipTv, ZipForge, Abbrevia and Delphi Zip. http://www.delphifaq.net/modules.php?name=FAQ&op=view&id=219 * How to encrypt/decrypt files using NTFS API - by m3rlin http://www.delphifaq.net/modules.php?name=FAQ&op=view&id=220 * Coding DB2 SQL for Performance: The Basics - by Craig S. Mullins Poorly coded SQL and application code can cause performance problems. This article is intended to give the basics of good SQL programming to application developers, particularly for those who are using Borland Kylix and Delphi RAD tools. http://www7b.software.ibm.com/dmdd/library/techarticle/0210mullins/ 0210mullins.html * Create a Reusable Component to Connect Delphi 7 to DB2 with dbExpress - by Bob Swart How to use IBM DB2 as the backend database for applications written with Delphi 7 and dbExpress. Specifically, how to connect the seven dbExpress components to DB2 and use them to build visual forms on top of database tables. http://www7b.software.ibm.com/dmdd/library/techarticle/0210swart/ 0210swart.html * Display and Modify DB2 Master-Detail Data in Delphi 7 Apps - Bob Swart A typical real world application will involve combining and displaying data from multiple tables in a usable format for reviewing and editing. This article shows how to add data and create relationships, manipulate the data from a Delphi application and get ready to move the entire package to Linux with Kylix. http://www7b.software.ibm.com/dmdd/library/techarticle/0211swart/ 0211swart.html * The Big Switch: Moving from Windows to Linux with Kylix 3 - Bob Swart One of the great things about using tools and databases such as Delphi IBM DB2 is that moving between platforms is only a matter of a few changes and a recompile. This article shows how to take the big jump and move a Delphi 7 application running on Windows to a Linux (Intel) application using Kylix 3. http://www7b.software.ibm.com/dmdd/library/techarticle/0211swart/ 0211swart2.html * Build DB2 and Delphi 7 Internet Applications with WebSnap - Bob Swart With Delphi 7 WebSnap technology, you can quickly take data from an IBM DB2 database and move it to a Web-based application in a snap. http://www7b.software.ibm.com/dmdd/library/techarticle/0211swart/ 0211swart3.html * Create Distributed DB2 and Delphi Web Apps with DataSnap - Bob Swart Enter the world of distributed applications, where you split your application into two different tiers: a thin client and a database server tier. This article focuses on the server side, as well as the communication between the client and the middleware server. http://www7b.software.ibm.com/dmdd/library/techarticle/0212swart/ 0212swart.html * DB2 and Delphi 7: SOAP and Database Web Services - by Bob Swart Creating a distributed application based on SOAP as the communication protocol, where the server (DB2) will be turned into a cross-platform Web Service. As a consequence, you can compile both the server and the client with Delphi 7 and Kylix 3 and deploy them on either Windows or Linux; this is a true cross-platform solution. http://www7b.software.ibm.com/dmdd/library/techarticle/0212swart1/ 0212swart1.html * Data Entry Input Validation With Delphi and Kylix - by Bob Swart How to build data entry forms on top of IBM DB2 Universal Database as database tables and records, and how to perform data entry validation using Delphi Studio and Kylix. Uses dbExpress and DB2 PE v8.1. http://www7b.software.ibm.com/dmdd/library/techarticle/0303swart/ 0303swart.html * Drill Into DB2 Tables for Decision Support Using Delphi - by Bob Swart How to build decision-support functionality by drilling into IBM DB2 tables using the Decision Cube component of Delphi. Uses dbExpress to connect to the DB2 UDB Personal Edition v7.x database. http://www7b.software.ibm.com/dmdd/library/techarticle/0304swart/ 0304swart.html * DB2 + SOAP: Database Web Services Follow-up with DataSnap - Bob Swart This extended DataSnap SOAP example covers deployment issues and some login and authentication details that help increase security for the DB2 backend database. http://www7b.software.ibm.com/dmdd/library/techarticle/0305swart/ 0305swart.html * Building a Web Service in Delphi with a DB2 Backend - by Marco Cantł To help you get started with Web services this article shows you a practical SOAP Web service example built with Delphi and a test client that serves up data from an IBM DB2 Universal Database backend. http://www7b.software.ibm.com/dmdd/library/techarticle/0212cantu/ 0212cantu.html * Check Efficiency of Oracle Caching with this Report - Donald Burleson One of the most important areas of Oracle tuning is the management of the RAM data buffers. Not only is it useful to know the contents of Oracle data buffers, it's also interesting to watch them move about in the list. Try this report to check up on your caching effectiveness. http://builder.com.com/article.jhtml?id=u00320030422brl01.htm * Ensure data integrity with proper database design - by Susan Harkins Data is the backbone of application development, so data accuracy is imperative. Take advantage of referential integrity to protect your database from invalid data. http://builder.com.com/article.jhtml?id=u00320030507ssh01.htm * How to List all files in a directory? http://www.swissdelphicenter.ch/en/showcode.php?id=1725 * How to export a TStringGrid to a MS Word table? http://www.swissdelphicenter.ch/en/showcode.php?id=1726 * How to export an Excel Table to a TStringgrid? http://www.swissdelphicenter.ch/en/showcode.php?id=1728 * How to trap mouse events outside of my application? http://www.swissdelphicenter.ch/en/showcode.php?id=1729 * How to fill in MS Word Form Fields? http://www.swissdelphicenter.ch/en/showcode.php?id=1731 * How to read a BlobStream with TADOQuery from an AccessDB? http://www.swissdelphicenter.ch/en/showcode.php?id=1744 * User list on Windows NT - by Serhiy Perevoznyk http://www.delphi3000.com/articles/article_3637.asp * Do you want TWAIN? - by Maarten de Haan Delphi Scanner Support Framework as a component. http://www.delphi3000.com/articles/article_3638.asp * How to convert a Grid's Surfer to a Grid's Arcview - by Camila Pinilla This code is useful to load a raster Grd file from surfer to ArcView when you want to interpolate data by using Sufer and then loading the grid by using Raster Arcview. http://www.delphi3000.com/articles/article_3639.asp * Component to calculate a Regression Multiple of set data - C Pinilla This code was used in a mathematical model to calculate a Regression Multiple in many points of a computational mesh. http://www.delphi3000.com/articles/article_3640.asp * An easy procedure to draw a Vector Field - by Camila Pinilla Useful if you have to draw a velocity field in a two dimensional mesh. http://www.delphi3000.com/articles/article_3641.asp * Choosing a ZIP Library for Delphi - by Mark Steinberg http://www.delphi3000.com/articles/article_3644.asp * How to create a dynamic PopUpMenu - by Christoph Otto Have you ever wanted to Create a PopupMenu at a Position you wanted? E.g. from a button going up. Here's how using TrackPopupMenuEx. http://www.delphi3000.com/articles/article_3647.asp * Secure compression component - by Ronald Douson A discussion on chosing a component for compressing files with strong encryption. http://www.delphi3000.com/articles/article_3648.asp * Fast Sine and Cosine Calculations - by John Pears How to really speed up sine and cosine calculations (in degrees). http://www.delphi3000.com/articles/article_3649.asp * Understanding pointers: for the amateurs - by Martin Strand Written for all the beginners out there. http://www.delphi3000.com/articles/article_3650.asp * WebSnap III: use of Adapter instead of Html Transparent Tags - by Eber Irigoyen The use of adapters to manage content in your web pages. Perhaps easier to use than html transparent tags? http://www.delphi3000.com/articles/article_3651.asp * TreeView control DragDrop Operation helper functions - by Wei Bao Make Treeview dragdrop operation programming simpler: automatic expand and collapse, move with children nodes, disable drop to child and self, auto scroll while the cursor near top or bottom of the control. http://www.delphi3000.com/articles/article_3652.asp * INI to XML- by Jim McKeeth INI was the old way to store settings (outside the registry), now everything is XML. This routine will convert an INI file into an XML node of a document. http://www.delphi3000.com/articles/article_3654.asp * Moving items in a TListBox using the mouse - by Christophe Geers A quick example on how to move items in a TListBox using the mouse. http://www.delphi3000.com/articles/article_3655.asp * A lot of DLLs with forms, Load dynamically into a PageControl of a Main-Form - by Manfred Suesens How to put DLL-Forms as Parent to a MainForm-PageControl-TabSheet. http://www.delphi3000.com/articles/article_3656.asp * Internet Explorer Automation - by Teun Spaans How to integrate IE into your application. http://www.delphi3000.com/articles/article_3657.asp * Next or Prev working Day - by Andreas Schmidt How to calculate the next/prev working day starting from a given date. http://www.delphi3000.com/articles/article_3658.asp * Creating a Delphi-Expert (Part I) - by Daniel Wischnewski The simplest way of creating a Delphi-Expert. http://www.delphi3000.com/articles/article_3661.asp * Create "Wait.." panel in design time - Miquel Taule Quick way to create a panel message. http://www.delphi3000.com/articles/article_3666.asp * Reading + Writing System-Wide Environment Variables - Richard Winston How do you set an environment variable that will apply outside the process that set the variable or those spawned by it? http://www.delphi3000.com/articles/article_3669.asp * Automatically start a service after using /Install or /Uninstall switch - by Brian Gochnauer Have you ever wished that the service would also start after installing the service not just install itself. http://www.delphi3000.com/articles/article_3671.asp * Captions in the DBNavigator - by Victor Dalvi http://www.delphi3000.com/articles/article_3672.asp * Users Take Open Source Databases for a Spin - by John Cox A growing number of companies are finding that open source databases are reaching a state where they can become the latest addition to their inventory of open source tools. http://www.nwfusion.com/news/2003/0428specialfocus.html * The Art of Enbugging - by Andy Hunt and Dave Thomas An article from IEEE Software about reducing the errors in your code through decoupling techniques. http://www.pragmaticprogrammer.com/articles/jan_03_enbug.pdf White Papers ------------ * Cross-platform Development with Borland RAD Tools - by Borland Traditionally, developers create and maintain separate programs for Windows and Linux platforms. Borland makes it possible to target both platforms with a single application. This white paper gives you an overview of what you can do including multi-tier apps, Web apps, and integration with Web services. http://bdn.borland.com/article/images/29139/ xplatform_with_borland_rad_tools.pdf * Database Application Development Using Borland Kylix and DB2 UDB v7.2 - by Paul Yip (IBM) and Ramesh Theivendran (Borland) Kylix is a RAD tool that provides a thin, cross-platform, database- independent, disconnected data-access model that can be used to quickly develop database applications for Linux and Windows platforms. By combining Kylix and DB2, you can write applications once and deploy them to run natively on both Linux and Windows without code changes. http://www-3.ibm.com/software/data/pubs/papers/kylix/kylix.pdf Tutorials ========= * A Beginner's Guide to Delphi: Chapter 13 - by Zarko Gajic It's time to learn how to let Delphi help you code faster: start using code templates, code insight, code completion, shortcut keys, etc. http://delphi.about.com/library/weekly/aa020202a.htm * Creating Simple User Object Property Dialogs - by Brian Frost A neat way of creating simple user object property dialogs that avoids spending ages wiring up controls to object properties. http://www.thedelphimagazine.com/samples/1614/1614.htm * Fun With OpenGL - by Dave Jewell Insights into the OpenGL graphics library and what it can do for your applications, demonstrating that it's not as difficult as you might think and it isn't all chocolate teapots, either! http://www.thedelphimagazine.com/samples/1445/1445.htm * Relational Databases: Defining Relationships Between Database Tables - by Susan Harkins Database normalization is the cornerstone of database theory. Once a database is normalized, relationships between the data in multiple tables must be established. http://builder.com.com/article.jhtml?id=u00320030430ssh01.htm * How to Program the Lego Mindstorms Robotic Kit - by Geert Barandat Tutorial of the Lego® Mindstorms® robotics kit and how to program it with Delphi. Topics include an introduction to ActiveX, PC-RCX interfacing and building autonomous robots. http://www.barandat.be/mindstorms/ Other Links =========== * The Quick Reference Site The ultimate resource for free IT Quick Reference Cards and e-books. http://www.digilife.be/quickreferences/indexe.html * Delphi Informant Magazine Readers Choice Awards 2003 Each year, Delphi Informant Magazine recognizes outstanding products and vendors in the Delphi add-on market. Please take a moment to select your favorite Delphi tools. This is your chance to voice your opinions regarding the tools and products you use in your everyday development efforts. http://www.delphizine.com/ballot2003/ News ==== * Borland Janeva Janeva provides seamless, high-performance interoperability between the Microsoft .NET Framework applications and the J2EE and CORBA infrastructures, allowing .NET client- or server-based applications to access J2EE and CORBA server-side components through the highly scalable and secure Internet Inter-ORB Protocol (IIOP). Janeva is tightly integrated with popular development environments for the Microsoft .NET Framework, including Microsoft Visual Studio for .NET and Borland C#Builder. Janeva helps accelerate the application lifecycle at a low total cost of ownership: implementation requires no expertise with J2EE or CORBA technologies, no change to back-end systems, and no additional hardware or software investments. http://www.borland.com/janeva/ Janeva in the news: - http://www.oreillynet.com/pub/wlg/3167 - http://news.com.com/2100-1012_3-999698.html - http://zdnet.com.com/2100-1104_2-999698.html - http://www.businessweek.com/technology/cnet/stories/999698.htm - http://www.nytimes.com/cnet/CNET_2100-1012_3-999698.html * Borland C#Builder The first independent development environment for the .NET Framework. C#Builder offers a design-driven approach to development that increases team productivity. C#Builder provides interoperability between .NET, J2EE and CORBA, so you can integrate different software systems. It also provides native support for major databases. http://www.borland.com/csharpbuilder/ * C# Builder box screen shots - by Anders Ohlsson A first look at the screen shots that are on the product boxes for Borland's new C# Builder (formerly Project Sidewinder). http://community.borland.com/article/0,1410,30021,00.html * Borland Makes .Net 'Life Cycle' Play - by Martin LaMonica Borland Software will take on software giant Microsoft with a suite of .Net development tools targeted at companies that program with both .Net and Java. http://news.com.com/2100-1012-997684.htm * Borland: Building Bridges Between Java and .Net - by ZDNet ZDNet Video interviews Dale Fuller, President and CEO, Borland. http://zdnet.com.com/1601-2-997475.html ________________________________________________________________________ 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/p0047.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!






