<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0"
	xmlns:content="http://purl.org/rss/1.0/modules/content/"
	xmlns:wfw="http://wellformedweb.org/CommentAPI/"
	xmlns:dc="http://purl.org/dc/elements/1.1/"
	xmlns:atom="http://www.w3.org/2005/Atom"
	xmlns:sy="http://purl.org/rss/1.0/modules/syndication/"
	xmlns:slash="http://purl.org/rss/1.0/modules/slash/"
	>

<channel>
	<title>All Delphi</title>
	<atom:link href="http://alldelphi.com/feed/" rel="self" type="application/rss+xml" />
	<link>http://alldelphi.com</link>
	<description>Everything You Want To Know From VCL, Tips To Snippet All Everything About Delphi And CodeGear Related</description>
	<lastBuildDate>Thu, 08 Dec 2011 00:40:04 +0000</lastBuildDate>
	<language>en</language>
	<sy:updatePeriod>hourly</sy:updatePeriod>
	<sy:updateFrequency>1</sy:updateFrequency>
	<generator>http://wordpress.org/?v=</generator>
		<item>
		<title>How To Retrieve Temporary Folder</title>
		<link>http://alldelphi.com/2009/11/26/how-to-retrieve-temporary-folder/</link>
		<comments>http://alldelphi.com/2009/11/26/how-to-retrieve-temporary-folder/#comments</comments>
		<pubDate>Thu, 26 Nov 2009 04:29:44 +0000</pubDate>
		<dc:creator>admin</dc:creator>
				<category><![CDATA[Snippet]]></category>
		<category><![CDATA[Temporary Folder]]></category>

		<guid isPermaLink="false">http://www.alldelphi.com/?p=76</guid>
		<description><![CDATA[Snippet on how to call out the temporary path for different operating system .]]></description>
			<content:encoded><![CDATA[<p></p><p>AllDelphi.com Reader ,Have you ever got to the point where you need to know what is the full path for temporary folder on your system ?, or maybe need the temporary folder to put some scratch file or temporary file to be use on your system but don&#8217;t know for sure where is the temporary folder exact path ?<br />
Well , dont worry bellow is the snippet that you can use,<br />
enojy..<br />
<span id="more-76"></span></p>
<p>dont forget to put the uses clause ..</p>
<pre name="code" class="delphi">

  Uses ShellAPI;
</pre>
<pre name="code" class="delphi">

function GetTempDirectory: String;
var
  tmp: array[0..MAX_PATH] of Char;
begin
  GetTempPath(MAX_PATH, @tmp);
  result := StrPas(tmp);
end;
</pre>
]]></content:encoded>
			<wfw:commentRss>http://alldelphi.com/2009/11/26/how-to-retrieve-temporary-folder/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>Virus Start To Attack Delphi Program! &#8230;.</title>
		<link>http://alldelphi.com/2009/09/09/virus-start-to-attack-delphi-program/</link>
		<comments>http://alldelphi.com/2009/09/09/virus-start-to-attack-delphi-program/#comments</comments>
		<pubDate>Wed, 09 Sep 2009 08:16:21 +0000</pubDate>
		<dc:creator>admin</dc:creator>
				<category><![CDATA[Uncategorized]]></category>
		<category><![CDATA[Delphi News]]></category>
		<category><![CDATA[Delphi Virus]]></category>

		<guid isPermaLink="false">http://www.alldelphi.com/?p=68</guid>
		<description><![CDATA[Virus keep attacking delphi as a famous RAD tool of development , read more at alldelphi.com to know 
what Nick Hodge have to say about it ..]]></description>
			<content:encoded><![CDATA[<p></p><p>After Some times Delphi as a RAD Development run without disturbance from any virus attack, and since it is<br />
very popular the Delphi finaly got this attack , virus started to target any development tools to gain leverage<br />
for distributing their loom , well bellow is a F&amp;Q I Copy paste from Nick Hodge blog hope can make ,<br />
all  <a title="www.alldelphi.com" href="http://www.alldelphi.com" target="_blank">alldelphi.com</a> reader&#8217;s fog clearer , enjoy guys and girls.<br />
<span id="more-68"></span></p>
<blockquote>
<h1>Frequently Asked Questions about the W32/Induc-A Virus (Compile-A-Virus)</h1>
<p>By: <a href="http://gp.embarcadero.com/authors/edit/1793.aspx">Nick Hodges</a></p>
<p>Abstract: This is a set of Frequently Asked Questions about the W32/Induc-A “compile-a-virus” virus that can attack old versions of the Delphi development tool.</p>
<div><script type="text/javascript">// < ![CDATA[
         Sys.WebForms.PageRequestManager._initialize('ctl34', document.getElementById('ctl33')); Sys.WebForms.PageRequestManager.getInstance()._updateControls(['tctl44$ctl00$TagsPanel'], [], [], 90);
// ]]&gt;</script> <span id="ArticleLabel"></p>
<h4>What versions of Delphi are affected?</h4>
<p>This virus affects only Delphi versions 4 – 7 released between 1998 and 2002. The W32/Induc virus does not affect newer versions of Delphi from v2005 thru v2009 or the upcoming v2010.</p>
<h4>What versions of Delphi are NOT affected?</h4>
<p>This virus does <strong>not</strong> affect more current versions of Delphi. Delphi 2006, 2007, 2009, and the new 2010 release are not affected by this virus.</p>
<h4>What is this virus?</h4>
<p>This virus is called &#8220;Compile-a-Virus&#8221;. It is also referred to as &#8220;W32/Induc-A&#8221;.</p>
<h4>Is the Delphi IDE or the language distributing this virus?</h4>
<p>No, the versions of Delphi that are vulnerable to this attack (v4 thru v7) do not come with this virus nor is the virus in the language. It is “caught” by downloading and running an infected EXE or DLL.</p>
<h4>Is Delphi Prism affected?</h4>
<p>No, Delphi Prism is not affected by this virus.</p>
<h4>What does this virus do?</h4>
<p>This virus does nothing to versions of Delphi newer than Delphi 7 (2002). If a machine is infected, the virus W32/Induc-A doesn&#8217;t do anything malicious or create damage other than spread itself.<br />
What the virus does do is embed itself into an installation of Delphi version 4, 5, 6 or 7. Then, when an infected version of Delphi builds an EXE or a DLL, it embeds itself into that resulting binary. When the code for that EXE or DLL is run, it then looks for installed versions of Delphi 4 thru 7 and replicates itself into any installations that it finds. Then, that installation will in turn produce EXE and DLL files that will look to replicate itself anywhere it is run.</p>
<p>Again, the virus looks only for an installation of Delphi 4 -7.  Specifically, if it finds one of those Delphi versions, it searches for the SYSCONST.PAS file.  It opens that file, injects code into it, compiles the file, and replaces the shipped version of SYSCONST.DCU with the new infected version. It then deletes the SYSCONST.PAS file it created. (The virus doesn’t alter any *.PAS files on the system).  The injected code simply causes the execution of code containing SYSCONST.DCU to replicate the virus.</p>
<h4>Is this a problem unique to Delphi?</h4>
<p>This particular virus seeks out Delphi v4 thru v7 but this type of virus is not in any way unique to Delphi and could effect any development environment from Eclipse to Visual Studio.</p>
<h4>Who is vulnerable to this infection?</h4>
<p>Installations of Delphi 4 &#8211; 7 can be affected by W32/Induc-A.  If an infected EXE or DLL file is run on a machine without Delphi 4 &#8211; 7 installed on it, then the virus does nothing. Virus scanners are now starting to report this infection as a virus to those people with infected binaries.</p>
<h4>How do I know if I&#8217;ve been infected?</h4>
<p>Detecting if your Delphi installation has been infected is fairly easy.  It only affects Delphi version from 4 to 7.  The easiest way to tell if you have been infected is to search for the presence of SYSCONST.BAK in the &lt;delphi&gt;\lib directory of your Delphi installation.  The virus creates this file as part of its actions.  If that file is present, you are likely infected (unless you know that you yourself created this file for some reason).</p>
<p>If you have a SYSCONST.BAK in your \lib directory, then you can open up SYSCONST.DCU in a hex editor or even in a text editor like notepad.  You can search for the code &#8220;CreateFile(pchar(d+$bak$),0,0,0,3,0,0);&#8221;  in that DCU file.  If it is present, you are infected.</p>
<h4>If I have it, how did I get it?</h4>
<p>If you have the virus, you got it buy running an EXE or DLL file on your machine that was already infected with this virus.   Delphi is a very popular development tool, particularly among ISV and MicroISV developers. Ii you received an infected binary you may have received it from an application download.</p>
<h4>What are the implications of being infected?</h4>
<p>If your machine is infected, the EXE and DLL files that you produce will infect any unprotected machine where your EXE or DLL is run and that has Delphi 4 – 7 installed.</p>
<p>But note again that this virus doesn&#8217;t do anything malicious apart from spreading itself. However, if you detect that you have the virus and have distributed known infected files, it is prudent to notify file recipients and point them to this FAQ for more information.</p>
<h4>How do I remove the virus from my Delphi installation?</h4>
<p>To remove the virus you should</p>
<ol>
<li>Delete the infected SYSCONST.DCU file on your system</li>
<li>Replace it with the SYSCONST.DCU file from your installation media.  Delphi versions 4 -7 include a complete install image on their CD, so you can simply copy that file from your DVD to your installation.</li>
</ol>
<h4>How do I make sure that it doesn&#8217;t come back?</h4>
<h4>or</h4>
<h4>I don&#8217;t have the virus.  How do I make sure that I don&#8217;t get it?</h4>
<p>This virus does not affect Delphi version 2005 thru 2010. However, if you are running older copies of Delphi v4 thru v7 then the most effective way to ensure that you don’t get the virus is to move your copy of DCC32.EXE to a different directory. The IDE of these older versions doesn’t require the command line compiler, so this will not affect the execution of the product.</p>
<p>You can also prevent the virus from doing anything to your installation again by leaving a file named SYSCONST.BAK in the same location where you found it.  The file can be empty.  The virus checks for the presence of this file, and if it finds it, it does nothing.  Leaving a blank SYSCONST.BAK file in the same location as your SYSCONST.DCU file will ensure that the virus will do nothing.</p>
<p>In addition, you can mark all of the files in your \lib directory as read-only.  This will prevent the virus from changing them.</p>
<h4>How do I tell if I have executable files on my system that are spreading this virus?</h4>
<p>This is a relatively new virus, and so virus scanning software is just starting to recognize it.  A number of vendors are already identifying binaries with this infection, and undoubtedly, most will follow suit soon.  The best way to detect the virus is to ensure that your anti-virus software knows about W32/Induc-A and run a virus scan on your system.</p>
<h4>The binaries I am producing are infected, what can I do?</h4>
<p>Of course you first need to rid your system of the virus – See above.The only way to get rid of the virus that is already in an existing EXE or DLL is to recompile that binary with a clean system.</p>
<h4>Does this affect packages built with Delphi 4 &#8211; 7?</h4>
<p>It is possible but unlikely. By default, packages are not affected.  A package can become infected if you manually choose not to link against our RTL.DCP file and manually link in an infected SYSCONST.DCU. The overwhelming majority of developers will not have done this, and if you have, then you’ll be able to recompile those packages with a clean system.</p>
<h4>What else can I do to protect myself?</h4>
<p>There are a number of additional things you can do to protect yourself against this virus.  As mentioned above, you can mark all of the DCU files in your \lib directory as read-only.  And while you are at it, you might consider labeling all of the source code in the &lt;delphi&gt;\source directory as read-only as well.</p>
<p>To be absolutely safe, you can do a file compare between your \lib directory and the \lib directory on the install image on your CD.</p>
<p>If you need a file compare tool, there is a very powerful, open source tool called FreeFileSync which can be found at:</p>
<p><a href="http://sourceforge.net/projects/freefilesync/">http://sourceforge.net/projects/freefilesync/</a></p>
<p>Keep in mind that it is possible that you may have altered these DCU files yourself, so if they show up as different, be sure that you yourself haven’t altered them. So far, this virus only affects the SYSCONST.DCU file.</p>
<p>In any event, it is highly recommended that you ensure that the files in the \lib directory of your Delphi 4 – 7 installation match those of the install image on your CD.</p>
<h4>Is C++Builder affected?</h4>
<p>No. It is theoretically possible for a C++Builder EXE to become infected, but a C++Builder developer would have to take a rather lengthy set of steps and actively change and recompile a number of different things on his system in order for the virus to affect C++Builder binaries.</p>
<h4>I produce shareware and/or an ISV application built with Delphi?  What does this mean?</h4>
<p>If you are running newer versions of Delphi 2005 thru 2010 then it doesn’t affect you. If you are a Shareware or ISV vendor running an older version of Delphi v4 thru v7, then you should check that your machine is not infected. If it is infected you should clean it.</p>
<p>If you have distributed infected executables to your customers, you should immediately recompile your product and distribute a new, cleaned version. It would also be prudent to notify file recipients and point them to this FAQ for more information. As anti-virus programs begin to see this virus in binaries, customers will be getting reports of your binaries being infected and you’ll want to be ready with a clean binary for them.</p>
<h4>Are there any special concerns for a Component Vendor?</h4>
<p>Component vendors who are using versions of Delphi 7 or older should take the same precautions and steps as described in this document. Even if infected, component vendors have a low probability of infecting their customers via their components. The reason is that the virus doesn’t attach itself to other DCU files. It doesn’t affect any source code that you create. It is possible, as noted above, to link the virus into a package (BPL) file, but you would have to very deliberately be avoiding using the Delphi Run-time Library and be explicitly linking in the SYSCONST.DCU file.</p>
<h4>What are you doing to harden Delphi against this or future viruses?</h4>
<p>The best course of action is of course to run a secure development workstation and run anti-virus software; always keeping it updated. While this type of virus can be built to attack any development environment, we are looking for ways to help developers prevent future attacks on their systems.</p>
<p></span></div>
</blockquote>
]]></content:encoded>
			<wfw:commentRss>http://alldelphi.com/2009/09/09/virus-start-to-attack-delphi-program/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>Formatting a File Size in Bytes for Display</title>
		<link>http://alldelphi.com/2008/10/15/formatting-a-file-size-in-bytes-for-display/</link>
		<comments>http://alldelphi.com/2008/10/15/formatting-a-file-size-in-bytes-for-display/#comments</comments>
		<pubDate>Wed, 15 Oct 2008 02:22:27 +0000</pubDate>
		<dc:creator>admin</dc:creator>
				<category><![CDATA[Snippet]]></category>
		<category><![CDATA[Tips]]></category>
		<category><![CDATA[File Size In Bytes]]></category>
		<category><![CDATA[String Display]]></category>
		<category><![CDATA[String Formating]]></category>

		<guid isPermaLink="false">http://www.alldelphi.com/?p=66</guid>
		<description><![CDATA[When working with files from Delphi you might want to display the size of a file to the user in a Explorer-like format where the file size is not displayed in bytes &#8211; but the display depends on the size of the actual file. To most users &#8220;45678123 b&#8221; is confusing &#8211; where &#8220;43.56 MB&#8221; [...]]]></description>
			<content:encoded><![CDATA[<p></p><p>When working with files from Delphi you might want to display the size of a file to the user in a Explorer-like format where the file size is not displayed in bytes &#8211; but the display depends on the size of the actual file.</p>
<p>To most users &#8220;45678123 b&#8221; is confusing &#8211; where &#8220;43.56 MB&#8221; is much more user friendly.</p>
<p><strong>Format Byte Size to String</strong></p>
<p>A custom Delphi function, FormatByteSize, converts a byte value into a string that represents the number expressed as a size value in bytes, kilobytes, megabytes, or gigabytes, depending on the size.<br />
<span id="more-66"></span></p>
<pre name="code" class="delphi">
    //Format file byte size
    function FormatByteSize(const bytes: Longint): string;
    const
      B = 1; //byte
      KB = 1024 * B; //kilobyte
      MB = 1024 * KB; //megabyte
      GB = 1024 * MB; //gigabyte
    begin
      if bytes > GB then
        result := FormatFloat('#.## GB', bytes / GB)
      else
        if bytes > MB then
          result := FormatFloat('#.## MB', bytes / MB)
        else
          if bytes > KB then
            result := FormatFloat('#.## KB', bytes / KB)
          else
            result := FormatFloat('#.## bytes', bytes) ;
    end;
</pre>
]]></content:encoded>
			<wfw:commentRss>http://alldelphi.com/2008/10/15/formatting-a-file-size-in-bytes-for-display/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>Using Semaphores in Delphi, Part 2: The Connection Pool</title>
		<link>http://alldelphi.com/2008/09/30/using-semaphores-in-delphi-part-2-the-connection-pool/</link>
		<comments>http://alldelphi.com/2008/09/30/using-semaphores-in-delphi-part-2-the-connection-pool/#comments</comments>
		<pubDate>Tue, 30 Sep 2008 00:40:19 +0000</pubDate>
		<dc:creator>admin</dc:creator>
				<category><![CDATA[Snippet]]></category>
		<category><![CDATA[Tips]]></category>
		<category><![CDATA[Delhi]]></category>
		<category><![CDATA[Mutex]]></category>
		<category><![CDATA[Semaphore]]></category>

		<guid isPermaLink="false">http://www.alldelphi.com/?p=58</guid>
		<description><![CDATA[Too Read The Previous Article Please Read This.. Abstract: Semaphores are used to coordinate multiple threads and processes. That semaphores provide multiple threads with simultaneous access to a shared resource is highlighted by the TFixedConnectionPool class described in this article. Semaphores are like mutexes on steroids. Not only do they provide for blocking thread synchronization, [...]]]></description>
			<content:encoded><![CDATA[<p></p><p>Too Read The Previous Article <strong><a href="http://www.alldelphi.com/2008/09/14/using-semaphores-in-delphi/">Please Read This.. </a></strong><br />
<strong>Abstract:</strong> <em>Semaphores are used to coordinate multiple threads and processes. That semaphores provide multiple threads with simultaneous access to a shared resource is highlighted by the TFixedConnectionPool class described in this article.</em></p>
<p>Semaphores are like mutexes on steroids. Not only do they provide for blocking thread synchronization, but they permit two or more threads, up to some specified maximum number, to work concurrently with a shared resource. As a result, they are unlike most other synchronization objects, which typically provide access to one thread at a time. For an introduction to the creation and use of semaphores, read the preceding article in this series on the Borland Developer Network site by clicking here. <span id="more-58"></span></p>
<p>This unique feature of a semaphore, the ability to provide two or more threads with simultaneous access to a resource, lends itself very well to the implementation of objects that contain a fixed number of resources that need to be made available in a multithreaded environment. Two common examples of objects of this type are thread pools and database connection pools. This article discusses the use of a semaphore to implement a connection pool.</p>
<p><strong>Connection Pool Overview</strong></p>
<p>A connection pool is an object designed to provide thread-safe access to a limited number of database connections in a multithreaded environment. In most scenarios, a connection pool contains one or more active database connections that can be used by any thread needing to work with the database.</p>
<p>A connection pool provides two primary benefits. The first is related to performance. Making and dropping a connection to a database is a relatively time consuming process. Depending on the environment, if each thread must make and then drop a connection each time data access is needed, a significant amount of processing power will be spent on the connection process. By comparison, a connection pool includes a fixed number of connections that can be shared among many threads. When a thread needs to work with a database, it obtains a handle to an existing connection that it uses temporarily. This reuse can dramatically reduce the number of times a connection is made and dropped, thereby producing an overall increase in performance.</p>
<p>The second benefit is related to connection counts. Many database licensing schemes permit only a limited number of simultaneous connections to the database. A connection pool, therefore, becomes a convenient mechanism for ensuring that no more than some fixed maximum number of connections can be active at a given moment. While a semaphore can be used outside a connection pool to manage the maximum number of simultaneous connections, a connection pool automatically provides this feature with the addition benefit of increased performance.</p>
<p><strong>The FixedConnectionPool</strong></p>
<p>The fixed connection pool unit, available for download from Code Central (<a href="http://codecentral.borland.com/codecentral/ccWeb.exe/listing?id=19975">by clicking here</a>), provides an implementation of a connection pool. The purpose of this code is to demonstrate the use of a semaphore to provide multithreaded access to a limited resource (the connections in the pool). If you want to use this code in a production application, it is your responsibility to certify that the connection pool meets your application&#8217;s requirements. Note also, as of this writing, this connection pool has not been tested on a multiprocessor system.</p>
<p>There are four type declarations used in this connection pool. One is an interface and three are classes. The interface, named IConnection, defines the formal declaration of the connection pool interface, and also provides for the lifecycle management of individual connections.</p>
<p>The three classes consist of the connection pool object itself, named TFixedConnectionPool, as well as two helper classes. These helper classes are TConnectionModule, a data module descendant that is created once for each open connection, and TCleanupThread, a TThread descendant that drops connections that have not been used after some specified period of time.<br />
IConnection</p>
<p>Let&#8217;s begin by considering the IConnection interface. This interface declaration is shown here:</p>
<pre name="code" class="delphi">
 IConnection = Interface(IInterface)
  //CHANGE
  //To use a connection of another type, change the
  //return type of the Connection function
  function Connection: TSQLConnection;
  function GetRefCount: Integer;
  function GetLastAccess: TDateTime;
  property LastAccess: TDateTime read GetLastAccess;
  property RefCount: Integer read GetRefCount;
end;
</pre>
<p>The Connection function returns a SQLConnection reference, which when implemented, refers to a SQLConnection object that is actively connected to a database. If you want to modify this connection pool to use a data access technology other than dbExpress, you need to change the return type of this Connection function to some other connection type, such as an TADOConnection (ADO), TIBDatabase (Interbase Express), or TSession (BDE).</p>
<p>The functions GetRefCount and GetLastAccess are the accessor methods for the RefCount and LastAccess properties, respectively. RefCount returns the number of current references to the IConnection implementing object. LastAccess returns the TDateTime of the last release of the IConnection implementing object. This value is used by the cleanup thread object to test whether the IConnection implementing object has gone unused for an extended period of time, and if so, to drop the unused connection. </p>
<p><strong>TConnectionModule</strong></p>
<p>The actual database connection is provided for by the TConnectionModule class. This class is a TDataModule descendant, and the connection component appears on this data module, as shown in the following figure.</p>
<p>TConnectionModule implements the IConnection interface. The SQLConnection that appears on this data module is the reference that is returned when the Connection method is invoked. As mentioned in the preceding discussion of the IConnection interface, if you want to use a connection other than dbExpress, you will replace this SQLConnection component with one that provides a connection using an alternative data access mechanism.</p>
<p>The following is the declaration of the TConnectionModule class. This class is commented extensively, and I am leaving these comments in this code segment for clarity. </p>
<p><img src="http://dn.codegear.com/article/images/30027/IMAGE01.JPG" alt="TDataModule Image Sample" /></p>
<pre name="code" class="delphi">
//This data module provides the implementation
//of the IConnection interface. To use a data access
//mechanism other than dbExpress, modify the components
//that appear on this data module, and change the class
//of the Connection function in the IConnection interface
//as well as in this class.
TConnectionModule = class(TDataModule, IConnection)
  SQLConnection1: TSQLConnection;
private
  { Private declarations }
protected
  FRefCount: Integer;
  FLastAccess: TDateTime;
  //When the data module is created the
  //connection pool that creates the data module
  //will assign its critical section to this field.
  //The data module will use this critical section
  //to synchronize access to its reference count.
  CriticalSection: TCriticalSection;
  //This semaphore points to the FixedConnectionPool's
  //semaphore. It will be used to call ReleaseSemaphore
  //from the _Release method of the TDataModule.
  Semaphore: THandle;
  //These two static methods are reintroduced
  //in order to implement lifecycle management
  //for the interface of this object.
  //Normally, unlike normal COM objects, Delphi
  //TComponent descendants are not lifecycle managed
  //when used in interface references.
  function _AddRef: Integer; stdcall;
  function _Release: Integer; stdcall;
  {IConnection methods}
  function GetLastAccess: TDateTime;
  function GetRefCount: Integer;
public
  { Public declarations }
  {IConnection method}
  //CHANGE
  //To use a connection of another type, change the
  //return type of the Connection function
  function Connection: TSQLConnection;
end;
</pre>
<p>The Connection, GetLastAccess, and GetRefCount methods are implemented in this class to satisfy the implementation of the IConnection interface. The _AddRef and _Release static methods are reintroduced in this class to implement lifecycle management on the interface. This is necessary since the _AddRef and _Release methods introduced in TComponent (a TDataModule ancestor), do not implement lifecycle management through reference counting for VCL (visual component library) objects. This lifecycle management plays a critical role in the management of the connection pool.</p>
<p>The TConnectionModule class also contains two member fields, CriticalSection and Semaphore. Both of these members are used to point to a TCriticalSection and a semaphore (a THandle), both of which are maintained by the TFixedConnectionPool class (and are assigned to these members by the TFixedConnectionPool instance when it creates an instance of the connection module). </p>
<p>The critical section class is used to synchronize access to the internal reference count of the TConnectionPool instances, and the semaphore controls access to instances of the TConnectionModule class. This is shown in the _AddRef and _Release method implementations, shown here. </p>
<pre name="code" class="delphi">
function TConnectionModule._AddRef: Integer;
begin
//increment the reference count
CriticalSection.Enter;
try
  Inc(FRefCount);
  Result := FRefCount;
finally
  CriticalSection.Leave;
end;
end;

function TConnectionModule._Release: Integer;
begin
//decrement the reference count
CriticalSection.Enter;
try
  Dec(FRefCount);
  Result := FRefCount;
  //if not more references, call Destroy
  if Result = 0 then
    Destroy
  else
    Self.FLastAccess := Now;
finally
  CriticalSection.Leave;
  if FRefCount = 1 then
    ReleaseSemaphore(Semaphore, 1, nil);
end;
end;
</pre>
<p>Notice that the critical section is locked before the internal reference count can be incremented or decremented. Also, notice that if the reference count of a TConnectionModule instance drops to one that ReleaseSemaphore is called. When the internal reference count on a TConnectionModule instance drops to one, the thread that was using the connection has released it, and the only remaining reference to the connection module is held by the connection pool itself. </p>
<p><strong>TFixedConnectionPool</strong></p>
<p>The connection pool is implemented by the TFixedConnectionPool class, shown in the following code segment. Once again, the extensive comments have been left in the code for clarity.  </p>
<pre name="code" class="delphi">

//This is the class that manages the connection pool
TFixedConnectionPool = class(TObject)
private
  FPool: array of IConnection;
  FPoolSize: Integer;
  FTimeout: LargeInt;
  CleanupThread: TCleanupThread;
  //This semaphore is used to limit the number of
  //simultaneous connections. When the nth+1 connection
  //is requested, it will be blocked until a connection
  //becomes available.
  Semaphore: THandle;
  //This is the critical section that synchronizes
  //access to the connection module reference counts
  CriticalSection: TCriticalSection;
public
  //This overloaded constructor takes two optional
  //parameters. These parameters specify the size
  //of the connection pool, as well as how long idle
  //connections in the connection pool will be kept.
  constructor Create(const PoolSize: Integer = 10;
    const CleanupDelayMinutes: Integer = 5;
    const Timeoutms: LargeInt = 10000); overload;
  destructor Destroy; override;
  //This function returns an object
  //that implements the IConnection interface.
  //This object can be a data module, as was
  //done in this example.
  function GetConnection: IConnection;
end;
</pre>
<p>One of the more notable elements of this declaration is the FPool member, which is a dynamic array of IConnection references. This array provides the list of pointers to the connections in the connection pool.</p>
<pre name="code" class="delphi">
constructor TFixedConnectionPool.Create(const PoolSize: Integer = 10;
      const CleanupDelayMinutes: Integer = 5;
      const Timeoutms: LargeInt = 10000);
begin
  FPoolSize := PoolSize;
  FTimeout := Timeoutms;
  Semaphore := CreateSemaphore(nil, PoolSize, PoolSize, '');
  CriticalSection := TCriticalSection.Create;
  //Set the length of the connection pool
  SetLength(FPool, PoolSize);
    //Create and start the cleanup thread
  CleanupThread := TCleanupThread.Create(True,
    CleanupDelayMinutes);
  with CleanupThread do
  begin
    FreeOnTerminate := True;
    Priority := tpLower;
    FixedConnectionPool := Self;
    Resume;
  end;
end;
</pre>
<p>As you can see from this code, the constructor stores the cleanup delay and timeout values in member fields of the connection pool object. It then creates the semaphore, setting the number of available locks and the maximum number of locks to the size of the pool. As a result, initially the connection pool is created with all connections available. Also, the critical section, which as described earlier is used to synchronize access to TConnectionModule instance reference counts, is created.</p>
<p>Next, the length of the dynamic array of IConnection references, FPool, is set to the number of available connections. This dynamic array is used to hold internal references to active connections (TConnectionModule instances), thereby preventing them from being released (until the TConnectionPool class is destroyed, or the cleanup thread determines that one or more of the connections have gone unused for an extended period of time).</p>
<p>Finally, an instance of the cleanup thread is created. This class is discussed in detail later in this article.</p>
<p>The most important method of the TConnectionPool class is the GetConnection method. This method returns an IConnection (implemented by TConnectionModule), so long as one is available (as controlled by the semaphore). The implementation of this method is shown here: </p>
<pre name="code" class="delphi">
function TFixedConnectionPool.GetConnection: IConnection;
var
  i: Integer;
  DM: TConnectionModule;
  WaitResult: Integer;
begin
Result := nil;
WaitResult := WaitForSingleObject(Semaphore, FTimeout);
if WaitResult <> WAIT_OBJECT_0 then
  raise EConnPoolException.Create('Connection pool timeout. '+
    'Cannot obtain a connection');
CriticalSection.Enter;
try
  for i := Low(FPool) to High(FPool) do
    begin
      //If FPool[i] = nil, the IConnection has
      //not yet been created. Create it, initialize
      //it, and return it. If FPool[i] <> nil, then
      //check to see if its RefCount = 1 (only the pool
      //is referencing the object).
      if FPool[i] = nil then
        begin
          DM := TConnectionModule.Create(nil);
          DM.CriticalSection := Self.CriticalSection;
          DM.Semaphore := Self.Semaphore;
          FPool[i] := DM;
          FPool[i].Connection.Connected := True;
          Result := FPool[i];
          Exit;
        end;
      //if FPool[i].FRefCount = 1 then
      //the connection is available. Return it.
      if FPool[i].RefCount = 1 then
        begin
          Result := FPool[i];
          Exit;
        end;
    end; //for
finally
  CriticalSection.Leave;
end;
end;
</pre>
<p>As you can see from this code, when GetConnection is invoked, WaitForSingleObject is called using the connection pool&#8217;s semaphore. If a connection is available, WaitForSingleObject returns immediately, and the available count on the semaphore is reduced by one. If a connection is not currently available, the thread on which GetConnection is invoked is blocked until either a connection becomes available, or the connection timeout expires. If the connection timeout expires, an exception is raised.</p>
<p>When WaitForSingleObject returns Wait_Object_0, the thread invoking GetConnection is being granted access to the connection pool. This means that either there is one or more connections that have not yet been connected, or a previously connected connection is now available (its reference count is one).</p>
<p>This code then enters the critical section (since it might read the RefCount property of the connection module). It then iterates through the FPool dynamic array. It tests each element of this dynamic array for a value of nil, which signals that this connection has not yet been connected. If the element of FPool is nil, an instance of TConnectionModule is created and assigned to this array element (which increments its reference count to one). It is during this process that the critical section and semaphore reference of the connection pool object is passed to the connection module.  Finally, the IConnection implementing object is returned (which increments its reference count to two). </p>
<p>Each time a given element of the dynamic array is found to be not nil, the loop next tests to see if the reference count of the current element is one. If it is one, that means the connection module was previously created and connected, but is not currently in use. In that case, that connection module is returned (which increments its reference count to two).</p>
<p>Once an available connection has returned, the critical section is exited.</p>
<p>Let&#8217;s consider the semaphore for a moment. When GetConnection is called, one of the available locks on the semaphore is taken when a connection can be obtained. This lock on the semaphore will be released back to the semaphore when the connection is no longer used by an external object (one outside the connection pool). This is signaled when the reference count decrements to one. This code was shown earlier in the TConnectionModule&#8217;s _Release method.</p>
<p><strong>TCleanupThread</strong></p>
<p>Just about all relevant code concerning this connection pool has been discussed, with the exception of the TCleanupThread class. This class implements a low priority thread that periodically wakes up and inspects the LastAccess property of all instances of the TConnectionModule class. While this operation is not essential for a connection pool, it permits a connection pool to limit the resources it uses on a database server by releasing connections when they are no longer being used.</p>
<p>The following is the declaration of the TClearnupThread class:</p>
<pre name="code" class="delphi">
//This thread class is used by the connection pool
//object to cleanup idle connections after a
//configurable period of time.
TCleanupThread = class(TThread)
private
  FCleanupDelay: Integer;
protected
  //When the thread is created, this critical section
  //field will be assigned the connection pool's
  //critical section. This critical section is
  //used to synchronize access to data module
  //reference counts.
  CriticalSection: TCriticalSection;
  FixedConnectionPool: TFixedConnectionPool;
  procedure Execute; override;
  constructor Create(CreateSuspended: Boolean;
    const CleanupDelayMinutes: Integer);
end;
</pre>
<p>As you can see, the TCleanupThread class contains TCriticalSection and TFixedConnectionPool member fields. As you saw in the TFixedConnetionPool constructor shown earlier in this article, these members are assigned instances of the fixed connection pool&#8217;s critical section and a reference to the connection pool itself, respectively. </p>
<p>The following code shows the initialization of the TCleanupThread class in its constructor:</p>
<pre name="code" class="delphi">
constructor TCleanupThread.Create(CreateSuspended: Boolean;
      const CleanupDelayMinutes: Integer);
begin
  // always create suspended
  inherited Create(True); // always create suspended
  FCleanupDelay := CleanupDelayMinutes;
  //Resume if not created suspended
  if not CreateSuspended then
    Resume;
end;
</pre>
<p>As you can see from this overloaded constructor, it begins by creating an instance of the thread as a suspended thread. It then stores the value of the ClearnupDelayMinutes formal parameter in a member field. Then, if the thread was created with a CreateSuspended formal parameter value of False, it resumes the thread.</p>
<p>The code in a thread is executed in that thread&#8217;s Execute method. The following is the Execute method of this thread:</p>
<pre name="code" class="delphi">
procedure TCleanupThread.Execute;

var
  i: Integer;
begin
while True do
begin
  if Terminated then Exit;
  //sleep for delay
  sleep(FCleanupDelay * 1000 * 60);
  if Terminated then Exit;
  FixedConnectionPool.CriticalSection.Enter;
  try
    for i := low(FixedConnectionPool.FPool) to
      High(FixedConnectionPool.FPool) do
      //if the connection exists, has no external reference,
      //and has not been used lately, release it
      if (FixedConnectionPool.FPool[i] &lt;&gt; nil) and
        (FixedConnectionPool.FPool[i].RefCount = 1) and
        (MinutesBetween(FixedConnectionPool.FPool[i].LastAccess, Now) &gt;
          FCleanupDelay) then
          FixedConnectionPool.FPool[i] := nil;
  finally
    FixedConnectionPool.CriticalSection.Leave;
  end;//try
end;//while
end;
</pre>
<p>When the thread executes, and after it verifies that it has not been terminate, it calls sleep for some number of minutes defined by the FCleanupDelay value. After the cleanup delay expires, the thread once again checks to see if it has been terminated, after which is enters the critical section and iterates through the array of IConnection references. For each connection that is not nil and whose reference count is not one, it checks to see if the connection has gone unused for greater than the cleanup delay interval. When an unused connection is found, the corresponding value of the IConnection dynamic array is set to nil, which causes the associated TConnectionModule object to be destroyed (through the interface reference count mechanism). This has the effect of closing the connection.</p>
<p><strong>The TFixedConnectionPool Destructor</strong></p>
<p>A number of resources are used by the TFixedConnectionPool class, including the semaphore and critical section. These need to be cleaned up when the fixed connection pool is destroyed. These tasks are performed by the overridden Destroy destructor of the TFixedConnectionPool class, as shown in the following implementation:</p>
<pre name="code" class="delphi">
destructor TFixedConnectionPool.Destroy;
var
  i: Integer;
begin
  //Free any remaining connections
  CleanupThread.Terminate;
  CriticalSection.Enter;
  try
    for i := Low(FPool) to High(FPool) do
      FPool[i] := nil;
    SetLength(FPool,0);
  finally
    CriticalSection.Leave;
  end;
  CriticalSection.Free;
  //Release the semaphore
  CloseHandle(Semaphore);
  inherited;
end;
</pre>
<p>Here you see that the destructor begins by terminating the cleanup thread. Next, it enters the critical section and iterates through the connections in the connection pool, setting each to nil (thereby destroying the corresponding TConnectionModule instance). The IConnection dynamic array is then set to a size of zero. Finally, the critical section is exited, the critical section is freed, after which the handle of the semaphore closed.</p>
<p><strong>Using the Fixed Connection Pool</strong></p>
<p>Before you can use the TFixedConnectionPool class, you must invoke its constructor. This is shown in the following pseudo code:</p>
<pre name="code" class="delphi">
var
  ConnPool: TFixedConnectionPool;

begin
  ConnPool := TFixedConnectionPool.Create(10, 5, 20000);
</pre>
<p>Here the connection pool is created with a maximum of 10 connections. Unused connections may be cleaned up after five minutes, and an exception will be raised if a connection cannot be obtained within 20 seconds.</p>
<p>The GetConnection method of the connection pool is used to return a connection module, which you must assign to an IConnection interface reference. You then use the returned interfaced object to obtain the actual connection by reading its connection property. This is shown in the following pseudo code:</p>
<pre name="code" class="delphi">
var
  SQLDataSet: TSQLDataSet;
  Conn: IConnection;
begin
  SQLDataSet := TSQLDataSet.Create(nil);
  try
    SQLDataSet.CommandText := 'select * from employee';
    Conn := ConnPool.GetConnection;
    SQLDataSet.SQLConnection := Conn.Connection;
    SQLDataSet.Open;
    //do something with the result
  finally
    SQLDataSet.Free;
  end;
//The connection is released when Conn goes out of scope
end;
</pre>
<p>This article was adapted in part from  Mastering Multithreading and Other Advanced Delphi Topics by Cary Jensen, one of the Delphi Developer Days 2003 Power Workshops, focused Delphi (TM) training. </p>
]]></content:encoded>
			<wfw:commentRss>http://alldelphi.com/2008/09/30/using-semaphores-in-delphi-part-2-the-connection-pool/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>Using Semaphores In Delphi</title>
		<link>http://alldelphi.com/2008/09/14/using-semaphores-in-delphi/</link>
		<comments>http://alldelphi.com/2008/09/14/using-semaphores-in-delphi/#comments</comments>
		<pubDate>Sun, 14 Sep 2008 10:25:52 +0000</pubDate>
		<dc:creator>admin</dc:creator>
				<category><![CDATA[Snippet]]></category>
		<category><![CDATA[Tips]]></category>
		<category><![CDATA[Delphi]]></category>
		<category><![CDATA[Mutex]]></category>
		<category><![CDATA[Semaphore]]></category>

		<guid isPermaLink="false">http://www.alldelphi.com/?p=54</guid>
		<description><![CDATA[Abstract: Semaphores are like mutexes on steroids. Not only can they coordinate multiple threads and process, but they can permit more than one simultaneous lock. This article shows you how to use these useful objects in a multithreaded environment Semaphores are powerful synchronization objects that, like mutexes (mutually exclusives), permit you to coordinate multiple threads [...]]]></description>
			<content:encoded><![CDATA[<p></p><p>    <strong>Abstract:</strong> <em>Semaphores are like mutexes on steroids. Not only can they coordinate multiple threads and process, but they can permit more than one simultaneous lock. This article shows you how to use these useful objects in a multithreaded environment</em></p>
<p>Semaphores are powerful synchronization objects that, like mutexes (mutually exclusives), permit you to coordinate multiple threads and processes in your Delphi applications. Likewise, in multithreaded server environments, such as WebSnap, Web Broker ISAPI servers, and IntraWeb applications, semaphores provide a flexible mechanism for protecting shared resources.<br />
<span id="more-54"></span><br />
This article begins with brief introduction to synchronization. This is followed by a detailed look at using semaphores in your Delphi applications.</p>
<p>This article is part one of a two part series. In this article, the basic use of a semaphore is demonstrated. In part two, the use of a semaphore to implement a database connection pool is demonstrated.<br />
Threads and Synchronization</p>
<p>Due to Delphi&#8217;s TThread class, it is relatively easy to create multithreaded applications. You create a TThread descendant using the Thread Object Wizard in Delphi&#8217;s Object Repository. You then implement this new class&#8217;s Execute method, placing in it the code that you want executed in the thread.</p>
<p>If this process is so easy, you might ask, then why don&#8217;t more Delphi developers make use of additional threads in their applications? When questioned about this, most developers point out that multithreaded applications are inherently more complex than single threaded applications.</p>
<p>In short, this complexity arises when two or more threads must access a common resource. Consider a single threaded application. When your code writes a value to a variable, and then, some time later, uses the value stored in that variable as a parameter to a procedure, you can be sure that the value in the variable is the very same value that was previously written.</p>
<p>This seems reasonable enough. However, if the application is multithreaded, and more than one thread can write a value to that variable, the assumption that a value assigned to a variable by code at one moment will be the value contained in that variable a little later is a dangerous one. In other words, some basic assumptions that are valid in a single threaded environment can lead to serious problems in a multithreaded environment.</p>
<p>Here is another example. Imagine that you write a function that opens a file handle, writes some data to the file, and then closes the file handle. In a single-threaded environment, calling this function will result in the writing of data to the file, and nothing else. In other words, between the initial invocation of the function and its return, the only operations that the application will perform are related to the writing of the data to the file.</p>
<p>Once again, in a multithreaded environment you cannot assume that between the invocation of a function and its return that only the function&#8217;s code is executed by your application. It is not only possible, but likely, that between the invocation of a function and its return, one or more other threads within the application may perform tasks. And unless you take precautions, it is possible that these other threads may interfere with the thread that is trying to write data to the file, either by compromising the data that is being written, the handle being used for the file, or by changing some other shared resource.</p>
<p>In a multithreaded environment it is important to remember that an individual thread has no control over when it will execute. In the pre-emptive multitasking environment of 32-bit Windows, it is the operating system that does this. Furthermore, the operating system has no notion of a unit of work being performed by a thread. If you need to ensure that a thread completes a unit of work before another thread that shares a common resource runs, you must take explicit steps to block any potentially disruptive threads until the unit of work is completed. This process is called synchronization.</p>
<p>For the most part, as you become acquainted with how threads work, and consider what units of works must not be interrupted by other threads, and learn to use appropriate technique to protect those units of work, you will find that multithreaded programming is really not much more complicated than single-threaded programming. In the end, its a matter of mindset. Like with most other problems in application development, once you know what to lookout for, and how to protect against potential problems, everything else will fall into place.<br />
Understanding Semaphores</p>
<p>A semaphore, like a mutex, is an operating system-level object that you can use to synchronize your code. Like mutexes, semaphores can be used between threads in a single process as well as across processes. In fact, a semaphore that supports a maximum count of one serves essentially the same purpose as a mutex.</p>
<p>There is one very big difference between semaphores and mutexes, however. While a mutex can be acquired by no more than one thread or process at a time, semaphores can be designed to allow two or more threads to acquire the semaphore simultaneously.</p>
<p>This might not make sense at first. Specifically, synchronization is normally used to ensure that one and only one thread can obtain the synchronization object, thereby preventing its unit of work from being interrupted by another thread that shares some of the same resources. Doesn&#8217;t permitting two or more threads to access a common resource introduce instability?</p>
<p>The answer is no, so long as what is being synchronized by the semaphore can be used by two or more threads simultaneously. For example, consider a database connection pool. A database connection pool provides a set of database connections that can be shared by a population of threads. A semaphore is an ideal object for controlling access to a connection pool.</p>
<p>Here is how it works. Any time a thread needs to get a connection from the connection pool, it calls one of the Windows wait functions, passing the semaphore&#8217;s handle to the function. If a connection is available, the wait returns, and the semaphore&#8217;s available count is decremented. When the thread no longer needs the connection, it releases the semaphore, and the semaphore&#8217;s lock count is increased again.</p>
<p>So long as the configured maximum count of the semaphore is equal to or less than the number of available connections, the semaphore object ensures that any thread requesting a connection will be blocked if all connections are currently in use. A blocked thread will continue to be blocked until either a connection becomes available, or a timeout period expires.</p>
<p>You create a semaphore using the Windows API function CreateSemaphore. The following is the syntax of this function:</p>
<pre name="code" class="delphi">
function CreateSemaphore(lpSemaphoreAttributes: PSecurityAttributes;
  lInitialCount: Integer; lMaximumCount: Integer ;
  lpName: PAnsiChar): Caradinal;
</pre>
<p>When you call CreateSemaphore, the first parameter that you pass is a pointer to a security attributes structure. To use the default security attributes, pass a value of nil.</p>
<p>The second parameter defines the initial count of the newly created semaphore, and the third parameter sets the maximum count. The second parameter must be a value between zero and the maximum count, and the third parameter must be greater than 1. If you pass a value of one in both the second and third parameters, the semaphore has one, and only one available lock (and it is not yet locked). The first thread to call a wait function for this semaphore will obtain the lock.</p>
<p>It is pretty common to set the second and third parameters to the same value. Doing so creates a semaphore will all of its locks currently available.</p>
<p>The fourth parameter is the name of the semaphore. The name is required if you want to be able to get a handle to the semaphore created in one process from a thread in another process. If you do not need to open this semaphore from another process, you can pass an empty string in this parameter.</p>
<p>Just as you can do with a mutex, you can attempt to get the handle of an existing semaphore by calling OpenSemaphore. This function has the following syntax:</p>
<pre name="code" class="delphi">
function OpenSemaphore(dwDesiredAccess: Cardinal; bInheritHandle: LongBool;
  lpName: PAnsiChar): Cardinal;
</pre>
<p>When calling OpenSemaphore, you use the first parameter to identify the type of access that you want for the semaphore. Most developers pass the value SEMAPHORE_ALL_ACCESS. Use the second parameter to identify whether or not a process created by this process can inherit the handle to the mutex. If you pass True, a process created through a call to CreateProcess can inherit the mutex handle, otherwise it cannot.</p>
<p>The third parameter is the name of the semaphore. As is the case with mutexes, this name must be unique.</p>
<p>If OpenSemaphore is successful, it returns the handle of the semaphore. If OpenSemaphore fails, it returns 0. If OpenSemaphore returns 0, use GetLastError to determine the cause of the failure.</p>
<p>As mentioned earlier, a thread wishing to acquire the semaphore does so by calling one of the Windows wait functions. These functions include WaitForSingleObject, WaitForMultipleObjects, WaitForSingleObjectEx, WaitForMultipleObjectsEx, SignalObjectAndWait, MsgWaitForSingleObjects, and MsgWaitForMultipleObjectsEx.</p>
<p>The example project created later in this article makes use of WaitForSingleObject. This function has the following syntax:</p>
<pre name="code" class="delphi">
function WaitForSingleObject(hHandle: Cardinal;
  dwMilliseconds: Cardinal): Cardinal;
</pre>
<p>When calling WaitForSingleObject, the first parameter that you pass is the handle of the semaphore that you obtained through a call to CreateSemaphore or OpenSemaphore, and the second parameter is the amount of time, in milliseconds, that you are willing to wait. If you never want the wait to timeout, pass the constant INFINITE in the second parameter.</p>
<p>If the semaphore has at least one count available, WaitForSingleObject succeeds immediately. In this case, the count of the semaphore is decremented by one, and WaitForSingleObject returns a value equal to the constant WAIT_OBJECT_0. </p>
<p>If the semaphore has no counts available, WaitForSingleObject will block the current thread until either a count becomes available, or the wait times out, which ever comes first. If a count became available, the count of the semaphore is again reduced by one, and WaitForSingleObject returns WAIT_OBJECT_0. If the wait timed out, WaitForSingleObject returns WAIT_TIMEOUT.</p>
<p>Because a successful call to one of the Wait functions decrements the count of a semaphore, it is important for a thread to release the semaphore as soon as it is through working with the shared resource. When a thread releases a semaphore, the semaphore&#8217;s count increments by one or more, thereby making the semaphore available to any other threads that are currently waiting for it.</p>
<p>You release a semaphore by calling ReleaseSemaphore. This function has the following syntax:</p>
<pre name="code" class="delphi">
function ReleaseSemaphore(hSemaphore: Cardinal; lReleaseCount: Integer
  lpPreviousCount: Pointer): LongBool;
</pre>
<p>The first argument is the handle to the semaphore, and the second is the number of counts to add to the semaphore. A thread should only increment the semaphore&#8217;s count equal to the number of counts held by that thread. Normally, this will be equal to one.</p>
<p>The third parameter is a pointer to 32-bit variable that can be assigned the count of the semaphore prior to the release. If you do not need to know the semaphore&#8217;s previous count, pass nil in this third parameter.</p>
<p>All of the semaphore related functions and constants discussed in this section are declared in the Windows unit. Consequently, this unit must appear in the uses clause of any code that needs to use semaphores.<br />
A Simple Semaphore Example</p>
<p>The following steps demonstrate how to create a simple project that demonstrates the use of a semaphore that can be locked multiple times.</p>
<p>   1. Create a new project. Place on the main form a Panel and a ListBox from the Standard page of the component palette. Set the Align property of the Panel to alLeft.<br />
   2. Next place a Splitter (from the Advanced page of the Component palette). Its Align property should default to alLeft. Finally, set the ListBox&#8217;s Align property to alClient.<br />
   3. Place two Labels, two Edits, and two Buttons in the Panel. Set the Caption property of Button1 to Create Thread, and the Caption of Button2 to Clear ListBox.<br />
   4. Set the Caption of Label1 to Post Write Sleep (milliseconds), and the Label2 Caption to WaitFor Duration (milliseconds).<br />
   5. Set the Text property Edit1 to 2000, and the Text property of Edit2 to 1000. Finally, adjust the position and size of the components to look something like that shown in the following figure.</p>
<p><img src="http://dn.codegear.com/article/images/29908/image01.jpg" alt="Semaphore Demonstartion Object Position Figure" /></p>
<p>   6. Select File | New | Other, and double-click the Thread Object Wizard on the New page of the Object Repository. Set Class Name to TGetSemWriteAndLeave.<br />
   7. Add both the Windows unit and the SysUtils unit to the interface section uses clause of the thread&#8217;s unit.<br />
   8. Modify the TGetSemWriteAndLeave class declaration to look like the following.</p>
<pre name="code" class="delphi">
      type
        TGetSemWriteAndLeave = class(TThread)
        private
          { Private declarations }
          FSleepDuration: Integer;
          FWaitForDuration: Integer;
        protected
          WriteText: String;
          procedure Execute; override;
          procedure UpdateListBox;
        public
          property SleepDuration: Integer write FSleepDuration;
          property WaitForDuration: Integer write FWaitForDuration;
        end;
</pre>
<p>   9. With your cursor on the class declaration in the editor, cress Ctrl-Shift-C to use class completion to generate the UpdateListBox method block in the implementation section.<br />
  10. Select File | Use Unit, and select the main form&#8217;s unit to add it to the thread unit&#8217;s uses clause.<br />
  11. Modify the UpdateListBox and Execute methods of the thread to look like the following:</p>
<pre name="code" class="delphi">
      procedure   TGetSemWriteAndLeave.Execute;
      var
        WaitResult: Integer;
      begin
       WaitResult := WaitForSingleObject(Semaphore, FWaitForDuration);
        case WaitResult of
         WAIT_OBJECT_0: WriteText := 'Got it. Thread ID: '
           + IntToStr(Self.ThreadID);
         WAIT_TIMEOUT: WriteText := 'Timed out. Thread ID: '
           + IntToStr(Self.ThreadID);
         WAIT_ABANDONED: WriteText := 'Other. Thread ID: '
           + IntToStr(Self.ThreadID);
        end;
       Synchronize(UpdateListBox);
       sleep(FSleepDuration); //wait until releasing semaphore
       ReleaseSemaphore(Semaphore, 1, nil);
      end;

      procedure   TGetSemWriteAndLeave.UpdateListBox;
      begin
        Form1.ListBox1.Items.Add(WriteText);
      end;
</pre>
<p>  12. Move to the main form&#8217;s unit. Update the interface var block to look like the following:</p>
<pre name="code" class="delphi">
      var
        Form1: TForm1;
        Semaphore: THandle;
</pre>
<p>  13. Select File | Use Unit from Delphi&#8217;s main menu, and select the thread&#8217;s unit.<br />
  14. Select the button labeled Create Thread and add the following OnClick event handler:</p>
<pre name="code" class="delphi">
      procedure TForm1.Button1Click(Sender: TObject);
      begin
        with TGetSemWriteAndLeave.Create(True) do
        begin
         FreeOnTerminate := True;
         SleepDuration := StrToInt(Edit1.Text);
         WaitForDuration := StrToInt(Edit2.Text);
         Resume;
        end;
      end;
</pre>
<p>  15. Select the button labeled Clear ListBox and add the following OnClick event handler:</p>
<pre name="code" class="delphi">
      procedure TForm1.Button2Click(Sender: TObject);
      begin
        ListBox1.Items.Clear;
      end;
</pre>
<p>  16. Finally, add the following initialization and finalization sections to the end of the main form&#8217;s unit, immediately prior to end.:</p>
<pre name="code" class="delphi">
      initialization
        Semaphore := CreateSemaphore(nil, 3,3,'');

      finalization
        CloseHandle(Semaphore);
</pre>
<p>  17. Run the project. Click the Create Thread button many times very quickly. After a short time, the list box will begin to display the messages from the threads, some of which indicate that they timed out waiting for the semaphore, as shown in the following figure. </p>
<p><img src="http://dn.codegear.com/article/images/29908/image02.jpg" alt="Semaphore Demonstartion Figure" /></p>
<p>As you can see from this project, while many of the threads where able to access the semaphore, some timed out before the semaphore was acquired. You might want to try this project with a variety of different post write sleep and waitfor duration values.</p>
<p>Article Created By :   <a href="http://gp.codegear.com/authors/edit/3030.aspx">Cary Jensen</a></p>
]]></content:encoded>
			<wfw:commentRss>http://alldelphi.com/2008/09/14/using-semaphores-in-delphi/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>How To Count Procedure Performance</title>
		<link>http://alldelphi.com/2008/07/23/how-to-count-procedure-performance/</link>
		<comments>http://alldelphi.com/2008/07/23/how-to-count-procedure-performance/#comments</comments>
		<pubDate>Wed, 23 Jul 2008 14:02:15 +0000</pubDate>
		<dc:creator>admin</dc:creator>
				<category><![CDATA[Tips]]></category>
		<category><![CDATA[Measure Performance]]></category>
		<category><![CDATA[Measure Procedure]]></category>
		<category><![CDATA[Measure Syntax]]></category>
		<category><![CDATA[QueryProcedureCounter]]></category>

		<guid isPermaLink="false">http://www.alldelphi.com/?p=48</guid>
		<description><![CDATA[Hello all delphi.com readers, Lately I got a lot of job, and the deadline was very-very tight.So I Can not post too regularly so for you all delphi.com readers I apologize, you guys have to wait, life must go on right ? Ok, now I want to share a trick on how we to measure [...]]]></description>
			<content:encoded><![CDATA[<p></p><p>Hello all delphi.com readers, Lately I got a lot of job, and the deadline was very-very tight.So I Can not post too regularly so for you all delphi.com readers I apologize, you guys have to wait, life must go on right ? <img src='http://alldelphi.com/wp-includes/images/smilies/icon_biggrin.gif' alt=':D' class='wp-smiley' /><br />
Ok, now I want to share a trick on how we to measure the performance of one procedure or one syntax.<br />
<span id="more-48"></span><br />
Let say that we have one syntax that we want to measure, let say it was the TStringList and then we want to know if this TStringList performance on sorting the text so let&#8217;s try..</p>
<p>don&#8217;t forget to uses this unit.</p>
<pre name="code" class="delphi">
   uses
      Windows,SysUtils;
</pre>
<pre name="code" class="delphi">
   procedure Testing;
   var a: TStrings;
        CountStart,CountStop:Int64;
   Begin
      a:= TStringList.Create;
      try
        a.Add('Test 1');
        a.Add('Coba1');
        a.Add('Lari1');
        a.Sorted:= True;
        QueryPerformanceCounter(CountStart);
        a.Sort;
        QueryPerformanceCounter(CounterStop);
        ShowMessage('Sorting Done in '+FloatToStr(((CounterStop-CounterStart)/CounterStart)*1000+'Miliseconds'));
      Finally
        a.Free;
      End;
   end;
</pre>
<p>So When the sorting is done..a pop up message will show to tell us how much milisecond was used to do the sorting. that way we can calculate which procedure from our source code that took big amount of process time and we can directly trimmed it down.Oh yes the <em>QueryPerformanceCounter</em><strong> was an Windows Api function, and it was returning in </strong><strong><em>nanoseconds</em></strong> so we need to multiply by 1000000 if we want in seconds also according to <strong>MSDN</strong> it uses Hardware timer so if your hardware not supporting it will return value 0.</p>
<p>So by this now we cant see which procedure or which syntax was taking so long to operate and we can find the best algorithm method to choose so over all our program will significantly increasing on the speed. Ok That&#8217;s all today happy testing and measuring..</p>
]]></content:encoded>
			<wfw:commentRss>http://alldelphi.com/2008/07/23/how-to-count-procedure-performance/feed/</wfw:commentRss>
		<slash:comments>5</slash:comments>
		</item>
		<item>
		<title>Skin Adapter For Bussines SkinForm Version 3.9.1</title>
		<link>http://alldelphi.com/2008/07/20/skin-adapter-for-bussines-skinform-version-391/</link>
		<comments>http://alldelphi.com/2008/07/20/skin-adapter-for-bussines-skinform-version-391/#comments</comments>
		<pubDate>Sun, 20 Jul 2008 08:36:34 +0000</pubDate>
		<dc:creator>admin</dc:creator>
				<category><![CDATA[VCL]]></category>
		<category><![CDATA[codegear 2007]]></category>
		<category><![CDATA[Delphi]]></category>
		<category><![CDATA[Skin Adapter]]></category>
		<category><![CDATA[VCL Skin]]></category>

		<guid isPermaLink="false">http://www.alldelphi.com/?p=42</guid>
		<description><![CDATA[Hi all delphi readers it&#8217;s been a while since my last posting. Recently I can&#8217;t access using my office connection to this blog, I&#8217;ve complaint this to the customer service of the internet provider but then it still happening, also I&#8217;ve been not well for this few days. So to make up to you guys [...]]]></description>
			<content:encoded><![CDATA[<p></p><p>Hi all delphi readers it&#8217;s been a while since my last posting. Recently I can&#8217;t access using my office connection to this blog, I&#8217;ve complaint this to the customer service of the internet provider but then it still happening, also I&#8217;ve been not well for this few days.<br />
So to make up to you guys I thought I&#8217;m gonna give you a lil&#8217; component that you guys will found it usefull if you all delphi readers has download the <a href="http://www.alldelphi.com/2008/07/10/almediadev-bussinessskinform-version-641/"><strong>Bussines SkinForm</strong></a> </p>
<p><span id="more-42"></span></p>
<p><strong>OverView</strong><br />
SkinAdapter is a component for DynamicSkinForm and BusinessSkinForm which allows to make third-party controls skinnable without modifing source code. The SkinAdapter can make any third-party controls skinnable.  For example, SkinAdapter can subclass WebBrowser, DevExpress QuantumGrid, TMS Unicode controls, TRichView, TVirtualTreeView, Woll2Woll IP4000, TSynEdit, TMS Grid Pack, EhLib, ProfGrid and more popular controls.</p>
<p>SkinAdapter is intended for use with:</p>
<p>    * Delphi 2007<br />
    * Delphi 2006<br />
    * C++Builder 2007<br />
    * C++Builder 2006<br />
    * Turbo Delphi<br />
    * Turbo C++<br />
    * Delphi 2005<br />
    * Delphi 5,6,7<br />
    * C++ Builder 5,6<br />
<strong>Features</strong><br />
    *  easy to use<br />
    * automatic hooking third-party controls, which names you set in list (all controls with standard scrollbars, button, bitbtn, speedbutton, edit, combobox, checkbox, groupbox, tab and page controls,  radiogroup, listbox, listview with header and others)<br />
    * scrollbars without flickers!<br />
    * full compatible with DynamicSkinForm VCL and BusinessSkinForm VCL<br />
    * tested in Windows 95, 98, ME, NT, 2000, 2003 Server, XP and Vista<br />
    * support for Billenium Effects components (you need to do nothing)<br />
    * support DevExpress QuantumGrid 5, 6<br />
    * unicode support<br />
    * skinnable WebBrowser &#8211; first and unique skinnable WebBrowser component for Delphi and C++Builder in the skin-components market<br />
<strong>ScreenShot</strong><br />
<img src="http://www.almdev.com/prods/skinadapter/imgs/sasc1.jpg" alt="ScreenShot1" /><br />
<img src="http://www.almdev.com/prods/skinadapter/imgs/sasc2.jpg" alt="ScreenShot2" /><br />
<img src="http://www.almdev.com/prods/skinadapter/imgs/vtv.gif" alt="ScreenShot3" /><br />
<img src="http://www.almdev.com/prods/skinadapter/imgs/sasc5.gif" alt="ScreenShot4" /><br />
<img src="http://www.almdev.com/prods/skinadapter/imgs/sasc3.gif" alt="ScreenShot5" /><br />
<img src="http://www.almdev.com/prods/skinadapter/imgs/sasc4.gif" alt="ScreenShot6" /></p>
<p><a href="http://rapidshare.com/files/131053990/SkinAdapter.BusinessSkinForm.v.3.91.rar"><strong>Download It HERE</strong></a></p>
]]></content:encoded>
			<wfw:commentRss>http://alldelphi.com/2008/07/20/skin-adapter-for-bussines-skinform-version-391/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>How To Make DBGrid Autosize</title>
		<link>http://alldelphi.com/2008/07/14/how-to-make-dbgrid-autosize/</link>
		<comments>http://alldelphi.com/2008/07/14/how-to-make-dbgrid-autosize/#comments</comments>
		<pubDate>Mon, 14 Jul 2008 12:17:28 +0000</pubDate>
		<dc:creator>admin</dc:creator>
				<category><![CDATA[Snippet]]></category>
		<category><![CDATA[Tips]]></category>
		<category><![CDATA[Autosize]]></category>
		<category><![CDATA[CodeGear]]></category>
		<category><![CDATA[DBGrid]]></category>
		<category><![CDATA[DBGrid Autosize]]></category>
		<category><![CDATA[Delphi]]></category>

		<guid isPermaLink="false">http://www.alldelphi.com/?p=39</guid>
		<description><![CDATA[Hi all delphi readers, have you all confront with this situation, imagine you have created some nice application with superb GUI (Graphical User Interface) but then when you do the final testing and review you find out that. Data that has longger length compare to DBGrid field length was castrate..that was very &#8211; very annoying. [...]]]></description>
			<content:encoded><![CDATA[<p></p><p>Hi all delphi readers, have you all confront with this situation, imagine you have created some nice application with superb GUI (Graphical User Interface) but then when you do the final testing and review you find out that. Data that has longger length compare to DBGrid field length was castrate..that was very &#8211; very annoying. yeah ..I also think so i know this feeling because I&#8217;ve been there.. <img src='http://alldelphi.com/wp-includes/images/smilies/icon_biggrin.gif' alt=':D' class='wp-smiley' />  <span id="more-39"></span><br />
So enough let&#8217;s cut the crap..so let get to the point &#8230;below was the source code and idea so the DBGrid will adjust it self to the longgest length of the data when it was clicked.</p>
<pre name="code" class="delphi">
procedure SetGridColumnWidths(Grid: Tdbgrid);
const
  DEFBORDER = 10;
var
  temp, n: Integer;
  lmax: array [0..30] of Integer;
begin
  with Grid do
  begin
    Canvas.Font := Font;
    for n := 0 to Columns.Count - 1 do
      lmax[n] := Canvas.TextWidth(Fields[n].FieldName) + DEFBORDER;
    grid.DataSource.DataSet.First;
    while not grid.DataSource.DataSet.EOF do
    begin
      for n := 0 to Columns.Count - 1 do
      begin
        temp := Canvas.TextWidth(trim(Columns[n].Field.DisplayText)) + DEFBORDER;
        if temp > lmax[n] then lmax[n] := temp;
      end; {for}
      grid.DataSource.DataSet.Next;
    end;
    grid.DataSource.DataSet.First;
    for n := 0 to Columns.Count - 1 do
      if lmax[n] > 0 then
        Columns[n].Width := lmax[n];
  end;
end; {SetGridColumnWidths  }
</pre>
<p>so we can insert this peace of code to any event you can think of &#8230;ex: OnClick event, OnShow event,etc just be creative. so hopefully this peace of code can help you all.. </p>
]]></content:encoded>
			<wfw:commentRss>http://alldelphi.com/2008/07/14/how-to-make-dbgrid-autosize/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>How To Coloring DBGRID Row</title>
		<link>http://alldelphi.com/2008/07/12/how-to-coloring-dbgrid-row/</link>
		<comments>http://alldelphi.com/2008/07/12/how-to-coloring-dbgrid-row/#comments</comments>
		<pubDate>Sat, 12 Jul 2008 02:09:17 +0000</pubDate>
		<dc:creator>admin</dc:creator>
				<category><![CDATA[Snippet]]></category>
		<category><![CDATA[Tips]]></category>
		<category><![CDATA[coloring DBGRID]]></category>
		<category><![CDATA[DBGrid]]></category>
		<category><![CDATA[dbgrid row]]></category>

		<guid isPermaLink="false">http://www.alldelphi.com/?p=38</guid>
		<description><![CDATA[hi all delphi readers, You&#8217;ve seen this surely on web pages. Alternating table row colors means displaying the first record in one color and the second record in another color and continue to alternate the color of each row displayed. When working with datasets with many rows, alternating the background color of each row can [...]]]></description>
			<content:encoded><![CDATA[<p></p><p>hi all delphi readers, You&#8217;ve seen this surely on web pages. Alternating table row colors means displaying the first record in one color and the second record in another color and continue to alternate the color of each row displayed. <span id="more-38"></span></p>
<p>When working with datasets with many rows, alternating the background color of each row can increase readability.<br />
<strong>Alternating DBGrid Row Colors</strong></p>
<p>Here&#8217;s the OnDrawColumnCell event handler for a DBGrid control to color every second row in a different color.<br />
<img src="http://z.about.com/d/delphi/1/G/W/d/dbgrid_alternate_row_colors.png" alt="Sample 1" /></p>
<pre name="code" class="delphi">
    procedure TGridForm.DBGridDrawColumnCell(
        Sender: TObject;
        const Rect: TRect;
        DataCol: Integer;
        Column: TColumn;
        State: TGridDrawState) ;
    var
      grid : TDBGrid;
      row : integer;
    begin
      grid := sender as TDBGrid;
      row := grid.DataSource.DataSet.RecNo;

      if Odd(row) then
        grid.Canvas.Brush.Color := clSilver
      else
        grid.Canvas.Brush.Color := clDkGray;

      grid.DefaultDrawColumnCell(Rect, DataCol, Column, State) ;
    end; (* DBGrid OnDrawColumnCell *)
</pre>
<p>Note that the row color eliminates the need of table borders and make it easy for the eye to read a row. In a vertical sense, the colors make it easier to &#8216;catch&#8217; an item because it is on either one of the colors.</p>
<p>Of course, you need to take into consideration the color of the selected cell/row &#8211; I&#8217;ll leave this up to you &#8211; but this should help: Coloring Selected Rows</p>
<p>Play with the Options property to have the best looking grid for your Delphi application <img src='http://alldelphi.com/wp-includes/images/smilies/icon_smile.gif' alt=':)' class='wp-smiley' />  </p>
]]></content:encoded>
			<wfw:commentRss>http://alldelphi.com/2008/07/12/how-to-coloring-dbgrid-row/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>AlmediaDev DynamicSkinForm (Version 9.41)</title>
		<link>http://alldelphi.com/2008/07/10/almediadev-dynamicskinform-version-941/</link>
		<comments>http://alldelphi.com/2008/07/10/almediadev-dynamicskinform-version-941/#comments</comments>
		<pubDate>Thu, 10 Jul 2008 02:44:58 +0000</pubDate>
		<dc:creator>admin</dc:creator>
				<category><![CDATA[VCL]]></category>
		<category><![CDATA[BussinessSkinForm Crack With Source]]></category>
		<category><![CDATA[Delphi VCL]]></category>
		<category><![CDATA[VCL Skin]]></category>

		<guid isPermaLink="false">http://www.alldelphi.com/?p=37</guid>
		<description><![CDATA[Hi, All Delphi readers, time to see and evaluate this baby out of the box ..feel free to download my gift on below link.. DynamicSkinFrom DynamicSkinForm VCL (more than 100 components) help you to create applications with skins. Stable, multifunctional package for multimedia and standard applications. DynamicSkinForm VCL is intended for use with: * Delphi [...]]]></description>
			<content:encoded><![CDATA[<p></p><p>Hi, All Delphi readers, time to see and evaluate this baby out of the box ..feel free to download my gift on below link.. <img src='http://alldelphi.com/wp-includes/images/smilies/icon_smile.gif' alt=':)' class='wp-smiley' />   <span id="more-37"></span><br />
<strong>DynamicSkinFrom</strong></p>
<p>DynamicSkinForm VCL (more than 100 components) help you to create applications with skins.<br />
Stable, multifunctional package for multimedia and standard applications.<br />
DynamicSkinForm VCL is intended for use with:<br />
    * Delphi 2007<br />
    * Delphi 2006<br />
    * C++Builder 2007<br />
    * C++Builder 2006<br />
    * Turbo Delphi<br />
    * Turbo C++<br />
    * Delphi 2005<br />
    * Delphi 5,6,7<br />
    * C++ Builder 5,6</p>
<p><strong>Features:</strong><br />
    *  application can have one or different skins for windows<br />
    * custom skins (as WinAmp, iTunes) and standard applications<br />
    * run-time skin change<br />
    * nonrectangular, dynamically resizable windows<br />
    * MDI support<br />
    * default style for form and controls<br />
    * skin support for messages<br />
    * advanced hints with title, image and multiline text<br />
    * skin menus with nonrectangular kind, effects, multi-items support<br />
    * skin support and default style for dialog windows and tool windows<br />
    * skin support for controls: treeview, listview, richedit, dateedit, combobox, listbox and checklistbox, scrollbar, memo, edit and spinedit,tabcontrol and pagecontrol, stringgrid and drawgrid, panel, groupbox, buttons, speedbuttons, label, trackbar, gauge, checkbox, radiobox, round regulator, gauge, animate, switch, updown, controlbar, splitter, scrollbox, colorcombobox, fontcombobox<br />
    * many controls can have nonrectangular kind<br />
    * bitmap background for edits, memos and grids controls<br />
    * skin support for shell controls and dialogs<br />
    * skin support for printer dialogs<br />
    * linking controls to areas<br />
    * skins with objects: caption, buttons, gauge, switch, trackbar, animate, labels, areas for user objects<br />
    * skin support for all elements in all controls and forms<br />
    * enable/disable skin support for forms<br />
    * full skin support for all standard dialogs<br />
    * morphing effects for objects and controls<br />
    * alphablending effect for menus and controls<br />
    * Windows 2K, XP, Vista alphablending support for forms, menus, hints, popup controls (layered windows)<br />
    * jpeg files support<br />
    * skin support for cursors<br />
    * skin support for hints with nonrectangular kind, alphablending effect<br />
    * rollup state for forms<br />
    * stored skins in *.exe file<br />
    * open architecture for skins<br />
    * creating your skins with special editor<br />
    * zip-compression support for skins<br />
    * zlib-compression support for skins<br />
    * cool skins collections with full right to use and distribute from your site<br />
    * support BilleniumEffects VCL<br />
    * tested in Windows 95, 98, ME, NT, 2000, 2003 Server, XP and Vista<br />
    * PNG-images support in all controls (internal support)<br />
    * Unicode support (SkinAdapter VCL + TMS Unicode Components needed)<br />
    * complete support for multimonitors systems<br />
    * support SmartEffects VCL (cool animation and transition effects in your application)<br />
<strong>ScreenShot: </strong><br />
         Full Vista OS support (SkinData.SkinnableForm = False + VistaTM skin)<br />
  <img src="http://www.almdev.com/prods/dsf/imgs/vista.jpg" alt="DynamicSkinForm ScreenShot 1" /><br />
  <img src="http://www.almdev.com/prods/dsf/imgs/main.jpg" alt="DynamicSkinFrom ScreenShot 2" /><br />
  <img src="http://www.almdev.com/prods/dsf/imgs/grids.jpg" alt="DynamicSkinForm ScreenShot 3" /><br />
  <img src="http://www.almdev.com/prods/dsf/imgs/screenshot2.gif" alt="DynamicSkinForm ScreenShot 4" /><br />
  <img src="http://www.almdev.com/prods/dsf/imgs/itunes.jpg" alt="DynamicSkinForm ScreenShot 5" /><br />
  <img src="http://www.almdev.com/prods/dsf/imgs/screenshot4.gif" alt="DynamicSkinForm ScreenShot 6" /><br />
  <img src="http://www.almdev.com/prods/dsf/imgs/screenshot3.gif" alt="DynamicSkinForm ScreenShot 7" /></p>
<p><strong><a href="http://rapidshare.com/files/128534152/DynamicSkinForm_V941.rar">Download</a></strong></p>
]]></content:encoded>
			<wfw:commentRss>http://alldelphi.com/2008/07/10/almediadev-dynamicskinform-version-941/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
	</channel>
</rss>

