<?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>Brandon Staggs .Com &#187; delphi</title>
	<atom:link href="http://www.brandonstaggs.com/tag/delphi/feed/" rel="self" type="application/rss+xml" />
	<link>http://www.brandonstaggs.com</link>
	<description>Software, Society, the Bible, Politics, and everything else.</description>
	<lastBuildDate>Mon, 15 Mar 2010 23:06:40 +0000</lastBuildDate>
	<generator>http://wordpress.org/?v=2.8.4</generator>
	<language>en</language>
	<sy:updatePeriod>hourly</sy:updatePeriod>
	<sy:updateFrequency>1</sy:updateFrequency>
			<item>
		<title>Give a Delphi TToolBar a Proper Themed Background</title>
		<link>http://www.brandonstaggs.com/2009/06/29/give-a-delphi-ttoolbar-a-proper-themed-background/</link>
		<comments>http://www.brandonstaggs.com/2009/06/29/give-a-delphi-ttoolbar-a-proper-themed-background/#comments</comments>
		<pubDate>Mon, 29 Jun 2009 21:46:24 +0000</pubDate>
		<dc:creator>Brandon</dc:creator>
				<category><![CDATA[Software & Technology]]></category>
		<category><![CDATA[delphi]]></category>

		<guid isPermaLink="false">http://www.brandonstaggs.com/?p=664</guid>
		<description><![CDATA[
A stock Delphi TToolBar will paint with a flat color or with a gradient. This is how a plain TToolBar appears in Windows Vista and Windows 7:

It looks okay, but Windows Vista has been around for a long time now, and this toolbar looks a bit dated. It doesn&#8217;t scream &#34;old,&#34; but it certainly doesn&#8217;t [...]]]></description>
			<content:encoded><![CDATA[<p align="center"><img src="/img/delphi-toolbar-themed/ttheme0.png" width="425" height="261"></p>
<p>A stock Delphi TToolBar will paint with a flat color or with a gradient. This is how a plain TToolBar appears in Windows Vista and Windows 7:</p>
<p align="center"><img src="/img/delphi-toolbar-themed/ttheme1.png" width="322" height="176"></p>
<p>It looks okay, but Windows Vista has been around for a long time now, and this toolbar looks a bit dated. It doesn&#8217;t scream &quot;old,&quot; but it certainly doesn&#8217;t pop out as &quot;shiny.&quot;</p>
<p>What we want to do is have the toolbar paint its background with the current operating system theme. This will give us a nice toolbar look that conforms to the current them, looks modern, and is backwards-compatible with Windows XP. Delphi (2007 and 2009) doesn&#8217;t offer us a property to do this, so we need to add some code to the toolbar&#8217;s OnCustomDraw event.</p>
<p>First, we add <strong>Themes</strong> to the form&#8217;s <strong>uses</strong> clause. The Themes unit contains Delphi routines for accessing the Windows XP and Vista Theme API.</p>
<pre>
uses
  Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms,
  Dialogs, ComCtrls, ImgList, ToolWin, StdCtrls, Menus, <strong>Themes</strong>;
</pre>
<p>Next, add the TToolBar&#8217;s OnCustomDraw event handler (double-click it under Events in the Object Inspector). And add the code to paint the background:</p>
<pre>
procedure TForm1.ToolBar1CustomDraw(Sender: TToolBar; const ARect: TRect;
  var DefaultDraw: Boolean);
var
  ElementDetails: TThemedElementDetails;
begin
  if ThemeServices.ThemesEnabled then
  begin
    ElementDetails := ThemeServices.GetElementDetails(trRebarRoot);
    ThemeServices.DrawElement(Sender.Canvas.Handle, ElementDetails, Sender.ClientRect);
  end;
end;
</pre>
<p>A little explanation:</p>
<p>ThemeServices.ThemesEnabled lets us know Themes are actually being used, so we don&#8217;t try to paint a theme element on a system that isn&#8217;t using themes. </p>
<p>The record variable ElementDetails is used to tell Windows what kind of theme object we want painted. In this case, we are using the rebar background, specified with a call to ThemeServices.GetElementDetails(trRebarRoot). We use ThemeServices.DrawElement to paint the rebar background on the TToolBar&#8217;s canvas.</p>
<p>This is how our Toolbar looks now:</p>
<p align="center"><img src="/img/delphi-toolbar-themed/ttheme2.png" width="322" height="176"> </p>
<p>With just a few lines of code, our application  looks like it has had a major face lift.</p>
<p>There is still something left that can be done to improve the appearance of the form a little more. Ideally, the toolbar should be blended a bit with the menu above it. You only need to do this if you are using a standard TMainMenu on the form&#8217;s Menu property to display your menu.</p>
<p>Change the OnCustomDraw event handler for the TToolBar so it looks like this:</p>
<pre>procedure TForm1.ToolBar1CustomDraw(Sender: TToolBar; const ARect: TRect;
  var DefaultDraw: Boolean);
var
  ElementDetails: TThemedElementDetails;
  <strong>NewRect : TRect;</strong>
begin
  if ThemeServices.ThemesEnabled then
  begin
    <strong>NewRect := Sender.ClientRect;</strong>
    <strong>NewRect.Top := NewRect.Top - GetSystemMetrics(SM_CYMENU);</strong>
    ElementDetails := ThemeServices.GetElementDetails(trRebarRoot);
    ThemeServices.DrawElement(Sender.Canvas.Handle, ElementDetails, <strong>NewRect</strong>);
  end;
end;
</pre>
<p>What we&#8217;ve done is introduced a new TRect so we can modify where the background painting starts. NewRect is initialized to the toolbar&#8217;s client rect coordinates. Then we use a call to GetSystemMetrics to get the height of a menu bar, and subtract that from the top of NewRect, and pass NewRect as the drawing rectangle to DrawElement. This starts the rebar background at the same position of the menu, giving us a more blended look for the toolbar:</p>
<p align="center"><img src="/img/delphi-toolbar-themed/ttheme3.png" width="322" height="176"> </p>
<p>Now the toolbar looks more &quot;attached&quot; to the menu bar.</p>
<p>Note that the toolbar paints well under Windows XP, too:</p>
<p align="center"><img src="/img/delphi-toolbar-themed/ttheme4.png" width="314" height="174"> </p>
<p>Giving a stock TToolBar a modern-looking background only takes a few lines of code and is an easy way to improve the appearance of your application. Once you&#8217;ve done this, you&#8217;ll want to start poking around in Themes.pas to see what else you can add some theme magic to. </p>
]]></content:encoded>
			<wfw:commentRss>http://www.brandonstaggs.com/2009/06/29/give-a-delphi-ttoolbar-a-proper-themed-background/feed/</wfw:commentRss>
		<slash:comments>1</slash:comments>
		</item>
		<item>
		<title>Implementing a Partial Serial Number Verification System in Delphi</title>
		<link>http://www.brandonstaggs.com/2007/07/26/implementing-a-partial-serial-number-verification-system-in-delphi/</link>
		<comments>http://www.brandonstaggs.com/2007/07/26/implementing-a-partial-serial-number-verification-system-in-delphi/#comments</comments>
		<pubDate>Thu, 26 Jul 2007 15:07:25 +0000</pubDate>
		<dc:creator>Brandon</dc:creator>
				<category><![CDATA[Software & Technology]]></category>
		<category><![CDATA[delphi]]></category>
		<category><![CDATA[misv]]></category>
		<category><![CDATA[programming]]></category>

		<guid isPermaLink="false">http://www.brandonstaggs.com/2007/07/26/implementing-a-partial-serial-number-verification-system-in-delphi/</guid>
		<description><![CDATA[Most micro-ISVs use a serial number/registration code system to allow end users to unlock or activate their purchase.  The problem most of us have run into is that a few days or weeks after our software is released, someone has developed a keygen, a crack, or has leaked a serial number across the internet.
There are [...]]]></description>
			<content:encoded><![CDATA[<p>Most micro-ISVs use a serial number/registration code system to allow end users to unlock or activate their purchase.  The problem most of us have run into is that a few days or weeks after our software is released, someone has developed a keygen, a crack, or has leaked a serial number across the internet.</p>
<p>There are several possible solutions to this problem. You could license a system like Armadillo/Software Passport or ASProtect, or you could distribute a separate full version as a download for your paying customers. Each option has advantages and disadvantages. What I am going to show you is a way to keep &#8220;rolling your own&#8221; license key system while making working cracks harder for crackers to produce, and working keygens a thing of the past.</p>
<p><span id="more-337"></span></p>
<p>Aside: If you think it&#8217;s crazy to post this publicly where crackers can see it, don&#8217;t worry about that. I&#8217;m not posting anything they haven&#8217;t seen before. The entire point of partial key verification is that your code never includes enough information to reverse engineer a key generation algorithm. Also, I offer no warranty of any kind &#8212; this is for your information only! Now, on with things.</p>
<p><strong>Our license key system must meet some basic requirements.</strong></p>
<ol type="1">
<li>License keys must be easy enough to type in.</li>
<li>We must be able to blacklist (revoke) a license key in the case of chargebacks or purchases with stolen credit cards.</li>
<li>No &#8220;phoning home&#8221; to test keys.  Although this practice is becoming more and more prevalent, I still do not appreciate it as a user, so will not ask my users to put up with it.</li>
<li>It should not be possible for a cracker to disassemble our released application and produce a working &#8220;keygen&#8221; from it. This means that our application will <em>not</em> fully test a key for verification. Only <em>some</em> of the key is to be tested. Further, each release of the application should test a <em>different</em> portion of the key, so that a phony key based on an earlier release will not work on a later release of our software.</li>
<li>Important: it should not be possible for a legitimate user to accidentally type in an invalid key that will appear to work but fail on a future version due to a typographical error.</li>
</ol>
<p>The solution is called a <em>Partial Key Verification System</em> because your software never tests the full key. Since your application does not include the code to test every portion of the key, it is impossible for a cracker to build a working valid key generator just by disassembling your executable code.</p>
<p>This system is <em>not</em> a way to prevent cracks entirely. It will still be possible for a cracker to edit your executable to jump over verification code. But such cracks only work on one specific release, and I&#8217;ll suggest a couple of tricks to make their job harder to complete successfully.</p>
<p>Let&#8217;s jump right in.  I&#8217;ll show you the system with Delphi code. (Given the readable nature of Delphi Pascal, you should be able to use these examples to build your own system in any language.)</p>
<p>An aside: if you think it&#8217;s crazy to post this publicly where crackers can see it, don&#8217;t worry! I&#8217;m not posting anything they don&#8217;t know. The whole point of this system is that your code never contains enough information for a cracker to reverse-engineer your key system. My blog post here doesn&#8217;t give them any information they don&#8217;t already have. Also, I&#8217;m not offering <em>any</em> kind of warranty with this information. This is for your information only, and all that. Now, on with things!</p>
<p><strong>1. The Key Format</strong></p>
<p>This example will create and test keys of 20 characters (with hyphens added for user convenience). A valid key will look like this:<br />
<tt>A279-1717-7D7A-CA2E-7154</tt></p>
<p>Once the hyphens are stripped, this is how the key breaks down:</p>
<table border="1" cellspacing="0" cellpadding="0">
<tbody>
<tr>
<td width="98" valign="top">
<p style="text-align: center">Seed value</p>
</td>
<td width="98" valign="top">
<p style="text-align: center">Key Byte 0</p>
</td>
<td width="98" valign="top">
<p style="text-align: center">Key Byte 1</p>
</td>
<td width="98" valign="top">
<p style="text-align: center">Key Byte 2</p>
</td>
<td width="98" valign="top">
<p style="text-align: center">Key Byte 3</p>
</td>
<td width="98" valign="top">
<p style="text-align: center">Checksum</p>
</td>
</tr>
<tr>
<td width="98" valign="top">
<p style="text-align: center">A2791717</p>
</td>
<td width="98" valign="top">
<p style="text-align: center">7D</p>
</td>
<td width="98" valign="top">
<p style="text-align: center">7A</p>
</td>
<td width="98" valign="top">
<p style="text-align: center">CA</p>
</td>
<td width="98" valign="top">
<p style="text-align: center">2E</p>
</td>
<td width="98" valign="top">
<p style="text-align: center">7154</p>
</td>
</tr>
</tbody>
</table>
<p>This sample system only uses four bytes for key verification, but a real system should use many more and larger values, so keep that in mind if you begin implementing your own PKVS.</p>
<p><strong>2. The Seed Value</strong></p>
<p>This sample system uses a 64-bit integer as a &#8220;seed&#8221; to generate the &#8220;Key Bytes&#8221; from.  The example project just generates random values for seeds, but when you implement a system like this, you must ensure that the seeds are always unique, because the seed is used when blacklisting a key. The seed could itself be a hash of a user name and time of generation, or any number of things</p>
<p><strong>3. Computing Key Bytes</strong></p>
<p>Here is the heart of the PKVS. Each &#8220;byte&#8221; of the key is a result of an operation on the seed value.  Here is a simple &#8220;byte&#8221; value computation function. It performs some bit twiddling based on the supplied parameters:</p>
<pre><strong><span>function</span></strong><span> PKV_GetKeyByte<strong>(const</strong> Seed <strong>:</strong> Int64<strong>;</strong> a<strong>,</strong> b<strong>,</strong> c <strong>:</strong> Byte<strong>)</strong> <strong>:</strong> Byte<strong>;
</strong></span><strong><span>begin
</span></strong><span>  a <strong>:=</strong> a <strong>mod</strong> <span style="color: #e00000">25</span><strong>;
</strong></span><span>  b <strong>:=</strong> b <strong>mod</strong> <span style="color: #e00000">3</span><strong>;</strong></span></pre>
<pre><span>  <strong>if</strong> a <strong>mod</strong> <span style="color: #e00000">2</span> <strong>=</strong> <span style="color: #e00000">0</span> <strong>then
</strong></span><span>    result <strong>:=</strong> <strong>((</strong>Seed <strong>shr</strong> a<strong>)</strong> <strong>and</strong> <strong>$</strong><span style="color: #e00000">000000FF</span><strong>)</strong> <strong>xor</strong> <strong>((</strong>Seed <strong>shr</strong> b<strong>)</strong> <strong>or</strong> c<strong>)
</strong></span><span>  <strong>else
</strong></span><span>    result <strong>:=</strong> <strong>((</strong>Seed <strong>shr</strong> a<strong>)</strong> <strong>and</strong> <strong>$</strong><span style="color: #e00000">000000FF</span><strong>)</strong> <strong>xor</strong> <strong>((</strong>Seed <strong>shr</strong> b<strong>)</strong> <strong>and</strong> c<strong>);
</strong></span><strong><span>end;</span></strong></pre>
<p>We&#8217;ll see in a moment how this function is used in the key generation and checking algorithms. Please keep in mind that this example function is very simplistic. A more effective function would use larger values than bytes and employ a more complex hashing system.</p>
<p><strong>4. We need a checksum</strong></p>
<p>Once we have our seed and bytes formed into a string of characters, we need to add a checksum to it. This way we can know when a user makes a mistake entering their key, without having to actually check each portion of the key for validity.</p>
<pre><strong><span>function</span></strong><span> PKV_GetChecksum<strong>(const</strong> s <strong>:</strong> <strong>String)</strong> <strong>:</strong> <strong>String;</strong></span></pre>
<pre><strong><span>var
</span></strong><span>  left<strong>,</strong> right<strong>,</strong> sum <strong>:</strong> Word<strong>;
</strong></span><span>  i <strong>:</strong> Integer<strong>;
</strong></span><strong><span>begin
</span></strong><span>  left <strong>:=</strong> <strong>$</strong><span style="color: #e00000">0056</span><strong>;
</strong></span><span>  right <strong>:=</strong> <strong>$</strong><span style="color: #e00000">00AF</span><strong>;</strong></span></pre>
<pre><span>  <strong>if</strong> Length<strong>(</strong>s<strong>)</strong> <strong>&gt;</strong> <span style="color: #e00000">0</span> <strong>then
</strong></span><span>    <strong>for</strong> i <strong>:=</strong> <span style="color: #e00000">1</span> <strong>to</strong> Length<strong>(</strong>s<strong>)</strong> <strong>do
</strong></span><span>    <strong>begin
</strong></span><span>      right <strong>:=</strong> right <strong>+</strong> Byte<strong>(</strong>s<strong>[</strong>i<strong>]);
</strong></span><span>      <strong>if</strong> right <strong>&gt;</strong> <strong>$</strong><span style="color: #e00000">00FF</span> <strong>then
</strong></span><span>        Dec<strong>(</strong>right<strong>,</strong> <strong>$</strong><span style="color: #e00000">00FF</span><strong>);
</strong></span><span>      Inc<strong>(</strong>left<strong>,</strong> right<strong>);
</strong></span><span>      <strong>if</strong> left <strong>&gt;</strong> <strong>$</strong><span style="color: #e00000">00FF</span> <strong>then
</strong></span><span>        Dec<strong>(</strong>left<strong>,</strong> <strong>$</strong><span style="color: #e00000">00FF</span><strong>);
</strong></span><span>    <strong>end;</strong></span></pre>
<pre><span>  sum <strong>:=</strong> <strong>(</strong>left <strong>shl</strong> <span style="color: #e00000">8</span><strong>)</strong> <strong>+</strong> right<strong>;
</strong></span><span>  result <strong>:=</strong> IntToHex<strong>(</strong>sum<strong>,</strong> <span style="color: #e00000">4</span><strong>);
</strong></span><strong><span>end;</span></strong></pre>
<p>This function computes a simple 8-bit value from the supplied string and returns it as a hexidecimal string, which we tack on to the end of our key.</p>
<p>Note that because this routine is always used to check a key in your application, a would-be keygen coder will be able to generate keys that pass the checksum test.  That&#8217;s okay.  The point of the checksum is only to prevent your users from mistyping their own valid license keys, and it will aid in determining if a key was deliberately forged.</p>
<p><strong>5. Putting it together: generating a valid key</strong></p>
<p>For our key generation program, we&#8217;re going to need a single function we can call to get a license key string from a seed value. Here it is:</p>
<pre><strong><span>function</span></strong><span> PKV_MakeKey<strong>(const</strong> Seed <strong>:</strong> Int64<strong>)</strong> <strong>:</strong> <strong>String;
</strong></span><strong><span>var
</span></strong><span>  KeyBytes <strong>:</strong> <strong>array[</strong><span style="color: #e00000">0..3</span><strong>]</strong> <strong>of</strong> Byte<strong>;
</strong></span><span>  i <strong>:</strong> Integer<strong>;
</strong></span><strong><span>begin
</span></strong><span>  <span style="color: blue">// Fill KeyBytes with values derived from Seed.
</span></span><span>  <span style="color: blue">// The parameters used here must be extactly the same
</span></span><span>  <span style="color: blue">// as the ones used in the PKV_CheckKey function.
</span></span><span>  <span style="color: blue">// A real key system should use more than four bytes.</span></span></pre>
<pre><span>  KeyBytes<strong>[</strong><span style="color: #e00000">0</span><strong>]</strong> <strong>:=</strong> PKV_GetKeyByte<strong>(</strong>Seed<strong>,</strong> <span style="color: #e00000">24</span><strong>,</strong> <span style="color: #e00000">3</span><strong>,</strong> <span style="color: #e00000">200</span><strong>);
</strong></span><span>  KeyBytes<strong>[</strong><span style="color: #e00000">1</span><strong>]</strong> <strong>:=</strong> PKV_GetKeyByte<strong>(</strong>Seed<strong>,</strong> <span style="color: #e00000">10</span><strong>,</strong> <span style="color: #e00000">0</span><strong>,</strong> <span style="color: #e00000">56</span><strong>);
</strong></span><span>  KeyBytes<strong>[</strong><span style="color: #e00000">2</span><strong>]</strong> <strong>:=</strong> PKV_GetKeyByte<strong>(</strong>Seed<strong>,</strong> <span style="color: #e00000">1</span><strong>,</strong> <span style="color: #e00000">2</span><strong>,</strong> <span style="color: #e00000">91</span><strong>);
</strong></span><span>  KeyBytes<strong>[</strong><span style="color: #e00000">3</span><strong>]</strong> <strong>:=</strong> PKV_GetKeyByte<strong>(</strong>Seed<strong>,</strong> <span style="color: #e00000">7</span><strong>,</strong> <span style="color: #e00000">1</span><strong>,</strong> <span style="color: #e00000">100</span><strong>);</strong></span></pre>
<pre><span> </span><span>  <span style="color: blue">// the key string begins with a hexidecimal string of the seed
</span></span><span>  result <strong>:=</strong> IntToHex<strong>(</strong>Seed<strong>,</strong> <span style="color: #e00000">8</span><strong>);</strong></span><span> </span></pre>
<pre><span>  <span style="color: blue">// then is followed by hexidecimal strings of each byte in the key
</span></span><span>  <strong>for</strong> i <strong>:=</strong> <span style="color: #e00000">0</span> <strong>to</strong> <span style="color: #e00000">3</span> <strong>do
</strong></span><span>    result <strong>:=</strong> result <strong>+</strong> IntToHex<strong>(</strong>KeyBytes<strong>[</strong>i<strong>],</strong> <span style="color: #e00000">2</span><strong>);</strong></span></pre>
<pre><span>  <span style="color: blue">// add checksum to key string
</span></span><span>  result <strong>:=</strong> result <strong>+</strong> PKV_GetChecksum<strong>(</strong>result<strong>);</strong></span></pre>
<pre><span>  <span style="color: blue">// Add some hyphens to make it easier to type
</span></span><span>  i <strong>:=</strong> Length<strong>(</strong>result<strong>)</strong> <strong>-</strong> <span style="color: #e00000">3</span><strong>;
</strong></span><span>  <strong>while</strong> <strong>(</strong>i <strong>&gt;</strong> <span style="color: #e00000">1</span><strong>)</strong> <strong>do
</strong></span><span>  <strong>begin
</strong></span><span>    Insert<strong>(</strong><span style="color: #00a000">'-'</span><strong>,</strong> result<strong>,</strong> i<strong>);
</strong></span><span>    Dec<strong>(</strong>i<strong>,</strong> <span style="color: #e00000">4</span><strong>);
</strong></span><span>  <strong>end;
</strong></span><strong><span>end;</span></strong></pre>
<p>Important: <em>never</em> compile this valid key generator function into your release application! It is only to be used on your end to generate valid keys. The success of a PKVS is based on keeping the parameters used in the PKV_GetKeyByte call <em>secret</em> and away from the prying eyes of crackers.  Remember: if it&#8217;s in your compiled executable, a cracker can see it!</p>
<p><strong>6. Testing a key in your application</strong></p>
<p>Your application needs two functions for testing a key.</p>
<p>The first is a function for testing <em>only</em> the checksum value.  You&#8217;ll use this to test the key when a user types it in.  To make it harder for a cracker, this is <em>all</em> you want to test at first. More on this later.</p>
<p>The second function actually verifies portions of the key to see if they are valid, and also checks against the blacklist to see if a key should be rejected based on its seed value.</p>
<p>First we need to define the constants:</p>
<pre><strong><span>const
</span></strong><span>  KEY_GOOD <strong>=</strong> <span style="color: #e00000">0</span><strong>;
</strong></span><span>  KEY_INVALID <strong>=</strong> <span style="color: #e00000">1</span><strong>;
</strong></span><span>  KEY_BLACKLISTED <strong>=</strong> <span style="color: #e00000">2</span><strong>;
</strong></span><span>  KEY_PHONY <strong>=</strong> <span style="color: #e00000">3</span><strong>;</strong></span><span> </span></pre>
<pre><span>  BL <strong>:</strong> <strong>array[</strong><span style="color: #e00000">0..0</span><strong>]</strong> <strong>of</strong> <strong>String</strong> <strong>=</strong> <strong>(
</strong></span><span>                                <span style="color: #00a000">'11111111'
</span></span><span>                               <strong>);</strong></span></pre>
<p>Above, BL is an array of blacklist strings. Important: only include the seed portion. Remember: if you put it in your program, a cracker can see it.  So do not put an entire key in the blacklist. That just makes it easier for a cracker to see what a valid key should look like.</p>
<p>Here is the checksum check function:</p>
<pre><strong><span>function</span></strong><span> PKV_CheckKeyChecksum<strong>(const</strong> Key <strong>:</strong> <strong>String)</strong> <strong>:</strong> Boolean<strong>;
</strong></span><strong><span>var
</span></strong><span>  s<strong>,</strong> c <strong>:</strong> <strong>String;
</strong></span><strong><span>begin
</span></strong><span>  result <strong>:=</strong> False<strong>;</strong></span></pre>
<pre><span>  <span style="color: blue">// remove cosmetic hypens and normalize case
</span></span><span>  s <strong>:=</strong> UpperCase<strong>(</strong>StringReplace<strong>(</strong>Key<strong>,</strong> <span style="color: #00a000">'-'</span><strong>,</strong> <span style="color: #00a000">''</span><strong>,</strong> <strong>[</strong>rfReplaceAll<strong>]));
</strong></span><span>  <strong>if</strong> Length<strong>(</strong>s<strong>)</strong> <strong>&lt;&gt;</strong> <span style="color: #e00000">20</span> <strong>then
</strong></span><span>    exit<strong>;</strong> <span style="color: blue">// Our keys are always 20 characters long</span></span></pre>
<pre><span>  <span style="color: blue">// last four characters are the checksum
</span></span><span>  c <strong>:=</strong> Copy<strong>(</strong>s<strong>,</strong> <span style="color: #e00000">17</span><strong>,</strong> <span style="color: #e00000">4</span><strong>);
</strong></span><span>  SetLength<strong>(</strong>s<strong>,</strong> <span style="color: #e00000">16</span><strong>);</strong></span></pre>
<pre><span>  <span style="color: blue">// compare the supplied checksum against the real checksum for
</span></span><span>  <span style="color: blue">// the key string.
</span></span><span>  result <strong>:=</strong> c <strong>=</strong> PKV_GetChecksum<strong>(</strong>s<strong>);
</strong></span><strong><span>end;</span></strong></pre>
<pre></pre>
<p>And finally, we come to the function that tests keys for validity. In the sample code, I am using conditional defines to allow me to easily exclude &#8220;key bytes&#8221; from the checking function, but you could just as easily comment them out.  My advice is to only include one or two checks in a release, and to change which ones are checked for each release. Again, our example only has four &#8220;check bytes&#8221; but you should use many more.</p>
<pre><strong><span>function</span></strong><span> PKV_CheckKey<strong>(const</strong> S <strong>:</strong> <strong>String)</strong> <strong>:</strong> Integer<strong>;
</strong></span><strong><span>var
</span></strong><span>  Key<strong>,</strong> kb <strong>:</strong> <strong>String;
</strong></span><span>  Seed <strong>:</strong> Int64<strong>;
</strong></span><span>  i <strong>:</strong> Integer<strong>;
</strong></span><span>  b <strong>:</strong> Byte<strong>;
</strong></span><strong><span>begin
</span></strong><span>  result <strong>:=</strong> KEY_INVALID<strong>;
</strong></span><span>  <strong>if</strong> <strong>not</strong> PKV_CheckKeyChecksum<strong>(</strong>S<strong>)</strong> <strong>then
</strong></span><span>    exit<strong>;</strong> <span style="color: blue">// bad checksum or wrong number of characters</span></span></pre>
<pre><span>  <span style="color: blue">// remove cosmetic hypens and normalize case
</span></span><span>  Key <strong>:=</strong> UpperCase<strong>(</strong>StringReplace<strong>(</strong>S<strong>,</strong> <span style="color: #00a000">'-'</span><strong>,</strong> <span style="color: #00a000">''</span><strong>,</strong> <strong>[</strong>rfReplaceAll<strong>]));</strong></span></pre>
<pre><span>  <span style="color: blue">// test against blacklist
</span></span><span>  <strong>if</strong> Length<strong>(</strong>BL<strong>)</strong> <strong>&gt;</strong> <span style="color: #e00000">0</span> <strong>then
</strong></span><span>    <strong>for</strong> i <strong>:=</strong> Low<strong>(</strong>BL<strong>)</strong> <strong>to</strong> High<strong>(</strong>BL<strong>)</strong> <strong>do
</strong></span><span>      <strong>if</strong> StartsStr<strong>(</strong>BL<strong>[</strong>i<strong>],</strong> Key<strong>)</strong> <strong>then
</strong></span><span>      <strong>begin
</strong></span><span>        result <strong>:=</strong> KEY_BLACKLISTED<strong>;
</strong></span><span>        exit<strong>;
</strong></span><span>      <strong>end;</strong></span></pre>
<pre><span>  <span style="color: blue">// At this point, the key is either valid or forged,
</span></span><span>  <span style="color: blue">// because a forged key can have a valid checksum.
</span></span><span>  <span style="color: blue">// We now test the "bytes" of the key to determine if it is
</span></span><span>  <span style="color: blue">// actually valid.</span></span></pre>
<pre><span>  <span style="color: blue">// When building your release application, use conditional defines
</span></span><span>  <span style="color: blue">// or comment out most of the byte checks!  This is the heart
</span></span><span>  <span style="color: blue">// of the partial key verification system. By not compiling in
</span></span><span>  <span style="color: blue">// each check, there is no way for someone to build a keygen that
</span></span><span>  <span style="color: blue">// will produce valid keys.  If an invalid keygen is released, you
</span></span><span>  <span style="color: blue">// simply change which byte checks are compiled in, and any serial
</span></span><span>  <span style="color: blue">// number built with the fake keygen no longer works.</span></span></pre>
<pre><span>  <span style="color: blue">// Note that the parameters used for PKV_GetKeyByte calls MUST
</span></span><span>  <span style="color: blue">// MATCH the values that PKV_MakeKey uses to make the key in the
</span></span><span>  <span style="color: blue">// first place!</span></span></pre>
<pre><span>  result <strong>:=</strong> KEY_PHONY<strong>;</strong></span></pre>
<pre><span>  <span style="color: blue">// extract the Seed from the supplied key string
</span></span><span>  <strong>if</strong> <strong>not</strong> TryStrToInt64<strong>(</strong><span style="color: #00a000">'$'</span> <strong>+</strong> Copy<strong>(</strong>Key<strong>,</strong> <span style="color: #e00000">1</span><strong>,</strong> <span style="color: #e00000">8</span><strong>),</strong> Seed<strong>)</strong> <strong>then
</strong></span><span>    exit<strong>;</strong></span><span> </span></pre>
<pre><span>  <span style="color: blue">{$IFDEF KEY00}
</span></span><span>  kb <strong>:=</strong> Copy<strong>(</strong>Key<strong>,</strong> <span style="color: #e00000">9</span><strong>,</strong> <span style="color: #e00000">2</span><strong>);
</strong></span><span>  b <strong>:=</strong> PKV_GetKeyByte<strong>(</strong>Seed<strong>,</strong> <span style="color: #e00000">24</span><strong>,</strong> <span style="color: #e00000">3</span><strong>,</strong> <span style="color: #e00000">200</span><strong>);
</strong></span><span>  <strong>if</strong> kb <strong>&lt;&gt;</strong> IntToHex<strong>(</strong>b<strong>,</strong> <span style="color: #e00000">2</span><strong>)</strong> <strong>then
</strong></span><span>    exit<strong>;
</strong></span><span>  <span style="color: blue">{$ENDIF}</span></span></pre>
<pre><span>  <span style="color: blue">{$IFDEF KEY01}
</span></span><span>  kb <strong>:=</strong> Copy<strong>(</strong>Key<strong>,</strong> <span style="color: #e00000">11</span><strong>,</strong> <span style="color: #e00000">2</span><strong>);
</strong></span><span>  b <strong>:=</strong> PKV_GetKeyByte<strong>(</strong>Seed<strong>,</strong> <span style="color: #e00000">10</span><strong>,</strong> <span style="color: #e00000">0</span><strong>,</strong> <span style="color: #e00000">56</span><strong>);
</strong></span><span>  <strong>if</strong> kb <strong>&lt;&gt;</strong> IntToHex<strong>(</strong>b<strong>,</strong> <span style="color: #e00000">2</span><strong>)</strong> <strong>then
</strong></span><span>    exit<strong>;</strong></span></pre>
<pre><span>  <span style="color: blue">{$ENDIF}</span></span></pre>
<pre><span>  <span style="color: blue">{$IFDEF KEY02}
</span></span><span>  kb <strong>:=</strong> Copy<strong>(</strong>Key<strong>,</strong> <span style="color: #e00000">13</span><strong>,</strong> <span style="color: #e00000">2</span><strong>);
</strong></span><span>  b <strong>:=</strong> PKV_GetKeyByte<strong>(</strong>Seed<strong>,</strong> <span style="color: #e00000">1</span><strong>,</strong> <span style="color: #e00000">2</span><strong>,</strong> <span style="color: #e00000">91</span><strong>);
</strong></span><span>  <strong>if</strong> kb <strong>&lt;&gt;</strong> IntToHex<strong>(</strong>b<strong>,</strong> <span style="color: #e00000">2</span><strong>)</strong> <strong>then
</strong></span><span>    exit<strong>;
</strong></span><span>  <span style="color: blue">{$ENDIF}</span></span><span> </span></pre>
<pre><span>  <span style="color: blue">{$IFDEF KEY03}
</span></span><span>  kb <strong>:=</strong> Copy<strong>(</strong>Key<strong>,</strong> <span style="color: #e00000">15</span><strong>,</strong> <span style="color: #e00000">2</span><strong>);
</strong></span><span>  b <strong>:=</strong> PKV_GetKeyByte<strong>(</strong>Seed<strong>,</strong> <span style="color: #e00000">7</span><strong>,</strong> <span style="color: #e00000">1</span><strong>,</strong> <span style="color: #e00000">100</span><strong>);
</strong></span><span>  <strong>if</strong> kb <strong>&lt;&gt;</strong> IntToHex<strong>(</strong>b<strong>,</strong> <span style="color: #e00000">2</span><strong>)</strong> <strong>then
</strong></span><span>    exit<strong>;
</strong></span><span>  <span style="color: blue">{$ENDIF}</span></span><span> </span></pre>
<pre><span>  <span style="color: blue">// If we get this far, then it means the key is either good, or was made
</span></span><span>  <span style="color: blue">// with a keygen derived from "this" release.</span></span></pre>
<pre><span>  result <strong>:=</strong> KEY_GOOD<strong>;
</strong></span><strong><span>end;</span></strong></pre>
<p><strong>6. Making it harder for crackers</strong></p>
<p>So far you have the tools you need to make a license key system that is virtually impervious to being &#8220;keygenned,&#8221; as far as valid keys go.  It is still possible for a cracker to alter your executable to skip key verification, and a cracker will still be able to create a keygen that works for whatever version of your application he has.  So what else is there to do?</p>
<ol type="A">
<li>The first step I suggest is <em>inlining</em> the PKV_GetKeyByte, PKV_GetChecksum, PKV_CheckKeyChecksum, and PKV_CheckKey functions. Recent versions of Delphi support the <strong>inline</strong> compiler directive that forces the compiler to &#8220;unroll&#8221; the function in-place rather than actually make a function call. This results in larger code, but also gives the cracker that many more places to examine while he is dissecting your executable. It also prevents him from finding the single entry point for PKV_CheckKey and making it always return KEY_GOOD.</li>
<li>When your application tests the stored key at startup, and when the user enters the key, <em>only check the checksum</em>. If your program immediately goes into its &#8220;key byte&#8221; verification code when it starts up or when the key is entered by the user, it&#8217;s just <em>asking</em> the cracker to watch carefully and see how it&#8217;s done!Just verify the checksum first, and give a polite error message if it is invalid (remember, this is where your customer is putting in his key that he gave you money for!). Elsewhere in your code, sprinkle the <em>real</em> checks into various operations.  User clicks File&gt;Save? There&#8217;s a good time to <em>really</em> check the key, instead of just the checksum. Perhaps set up a timer and check it a full minute after the code is entered.  The possibilities are endless, and any unique ideas you come up with will make your program that much more tedious for a cracker to work on.  Crackers have lots of programs to fool around with, and if yours gets to be too frustrating, they may get sloppy and release only a partially working crack, or skip your application altogether.</li>
<li>Keep on top of cracks, phony keygens, and leaked keys. Even though it isn&#8217;t possible for a cracker to create a <em>fully</em> valid key based on what you compiled into your program, he can (and probably will) release a keygen that works with whatever version he downloaded.  Set up a Google Alert for &#8220;Your_program keygen serial crack&#8221; and when one is released, immediately change which &#8220;key bytes&#8221; your program checks, or add the leaked key to the blacklist, and recompile. Suddenly none of the keys, keygens, and cracks released work anymore. Also, do a &#8220;silent&#8221; update of your download file when you are just recompiling for this reason. No need to announce to the cracker that their keygen suddenly doesn&#8217;t work any more.</li>
</ol>
<p><strong>7</strong><strong>. Further development</strong></p>
<p>This PKVS example is very simple in its implementation. There are several things that could be added to make it more powerful.</p>
<ol type="A">
<li>Replace PKV_GetKeyByte with a more robust version. There are many hashing algorithms available that can be used as a starting point for calculating the portions of your key used to determine if it is valid.  Using the sample function presented here would be a mistake as it could be reverse engineered with valid leaked keys and brute-force algorithms.</li>
<li>Instead of using hexidecimal, use the entire alphabet. This will let you pack a lot more data into the key string without making it too long. Note that the comparisons and byte generation checks in this example will have to be re-written to work with any other base numbering system.</li>
<li>The example implementation is a simple &#8220;serial number&#8221; system and does not tie the key to a user name or other information. However, it would be trivial to make the seed itself a checksum value of another string, such as the user&#8217;s name.</li>
<li>Anything could be added to the key string. You could add additional values to store activation or expiration dates, for example.</li>
<li>Your key generation system should maintain a database of issued keys. You should always test your key check function against every key you have issued.  Also, keep a database of blacklisted or leaked keys, and always test your check function against them to ensure it returns the expected results.</li>
</ol>
<p><strong>Concluding remarks</strong></p>
<p>Whatever you do, don&#8217;t focus all of your energy on your licensing system.  It is important, but creating usable software that customers need is more important. A good license key system will certainly improve your sales, but you can&#8217;t hope to convert every one searching for &#8220;MyProgram Serialz&#8221; into a customer.  A system like the one described here can be implemented in a day or two, but constantly trying to outsmart crackers is a never-ending battle.</p>
]]></content:encoded>
			<wfw:commentRss>http://www.brandonstaggs.com/2007/07/26/implementing-a-partial-serial-number-verification-system-in-delphi/feed/</wfw:commentRss>
		<slash:comments>12</slash:comments>
		</item>
		<item>
		<title>Delphi 2007 Update 1: CodeGear Delivers</title>
		<link>http://www.brandonstaggs.com/2007/06/16/delphi-2007-update-1-codegear-delivers/</link>
		<comments>http://www.brandonstaggs.com/2007/06/16/delphi-2007-update-1-codegear-delivers/#comments</comments>
		<pubDate>Sun, 17 Jun 2007 00:03:00 +0000</pubDate>
		<dc:creator>Brandon</dc:creator>
				<category><![CDATA[Software & Technology]]></category>
		<category><![CDATA[delphi]]></category>
		<category><![CDATA[review]]></category>

		<guid isPermaLink="false">http://www.brandonstaggs.com/wptest/?p=311</guid>
		<description><![CDATA[A while back I blogged about my major disappointments with Delphi 2007. I&#8217;m happy to say that the problems D2007 had, which prevented me from using it for project development, seem to have been adequately addressed with CodeGear&#8217;s first service pack.
To wit, I&#8217;ve just used Delphi 2007 Update 1 to compile what I hope to [...]]]></description>
			<content:encoded><![CDATA[<p>A while back I blogged about my major disappointments with <a target="_blank" href="http://www.codegear.com/products/delphi/win32">Delphi 2007</a>. I&#8217;m happy to say that the problems D2007 had, which prevented me from using it for project development, seem to have been adequately addressed with CodeGear&#8217;s first service pack.</p>
<p>To wit, I&#8217;ve just used Delphi 2007 Update 1 to compile what I hope to be the next release of <a href="http://www.dailybibleandprayer.com">Daily Bible and Prayer</a> &#8212; version 2.1, a small update. I was able to do all of the .1 development in D2007 without anything holding me back, and the finished product works as it should. If all goes well, DBAP 2.1 will be released (as a free update) later this week.</p>
]]></content:encoded>
			<wfw:commentRss>http://www.brandonstaggs.com/2007/06/16/delphi-2007-update-1-codegear-delivers/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>Delphi 2007 for Win32 Workarounds</title>
		<link>http://www.brandonstaggs.com/2007/04/03/delphi-2007-for-win32-workarounds/</link>
		<comments>http://www.brandonstaggs.com/2007/04/03/delphi-2007-for-win32-workarounds/#comments</comments>
		<pubDate>Tue, 03 Apr 2007 16:28:00 +0000</pubDate>
		<dc:creator>Brandon</dc:creator>
				<category><![CDATA[Software & Technology]]></category>
		<category><![CDATA[delphi]]></category>

		<guid isPermaLink="false">http://www.brandonstaggs.com/wptest/?p=300</guid>
		<description><![CDATA[My recent post on Delphi 2007&#8217;s problems with the taskbar and task manager list shouldn&#8217;t simply &#8220;sit there&#8221; &#8212; my disappointment is all well and fine, but what if you have D2007 and you need to make do before a hotfix is released?
Dave Nottage, always a helpful poster in the Delphi newsgroups, has succinct workarounds.
]]></description>
			<content:encoded><![CDATA[<p>My recent post on Delphi 2007&#8217;s problems with the taskbar and task manager list shouldn&#8217;t simply &#8220;sit there&#8221; &#8212; my disappointment is all well and fine, but what if you have D2007 and you need to make do before a hotfix is released?</p>
<p>Dave Nottage, always a helpful poster in the Delphi newsgroups, has <a target="_blank" href="http://blogs.teamb.com/davenottage/archive/2007/04/03/33687.aspx">succinct workarounds</a>.</p>
]]></content:encoded>
			<wfw:commentRss>http://www.brandonstaggs.com/2007/04/03/delphi-2007-for-win32-workarounds/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>Delphi 2007 for Win32: Oops!</title>
		<link>http://www.brandonstaggs.com/2007/03/27/delphi-2007-oops-earlier-this-month-i-blogged/</link>
		<comments>http://www.brandonstaggs.com/2007/03/27/delphi-2007-oops-earlier-this-month-i-blogged/#comments</comments>
		<pubDate>Wed, 28 Mar 2007 01:57:00 +0000</pubDate>
		<dc:creator>Brandon</dc:creator>
				<category><![CDATA[Software & Technology]]></category>
		<category><![CDATA[delphi]]></category>

		<guid isPermaLink="false">http://www.brandonstaggs.com/wptest/?p=298</guid>
		<description><![CDATA[Delphi 2007 &#8212; Oops!
Earlier this month I blogged about my enthusiasm about Delphi 2007 and CodeGear. I did so before D2007 was shipping based on what I saw in the betas. I meant every word of it.
But.
Hold on a bit. D2007 has shipped, but there exist a couple of serious problems. Suffice it to say [...]]]></description>
			<content:encoded><![CDATA[<p>Delphi 2007 &#8212; Oops!</p>
<p>Earlier this month I blogged about my enthusiasm about Delphi 2007 and CodeGear. I did so before D2007 was shipping based on what I saw in the betas. I meant every word of it.</p>
<p>But.</p>
<p>Hold on a bit. D2007 has shipped, but there exist a couple of serious problems. Suffice it to say I can&#8217;t build a production-level application with D2007 due to some nagging open issues &#8212; issues that should never have made it into the final release. It appears that CodeGear was so in need of revenue in 1Q 2007 that they simply had to get it out the door this month. Unfortunately, this means that it&#8217;s not good for releasing applications until they release a hotfix or two to address two major issues:</p>
<p>1. Task bar button stuff. Applications compiled with D2007 just don&#8217;t work right in this respect.</p>
<p>2. Applications compiled with D2007 don&#8217;t show up on the Windows task list. Ouch!</p>
<p>Of course, there are workarounds, but this is pretty disappointing. I&#8217;m not disclosing anything that comes from beta testing &#8212; this is stuff from the released version of D2007.</p>
<p>Why am I writing this? I opened my mouth (er, typed my keys) and said how great D2007 is. I owe it to anyone reading my blog to update them on it just in case it matters to them. D2007 is great, to be sure, but it&#8217;s just not done!</p>
<p>This isn&#8217;t really new, of course. D2005 wasn&#8217;t done when it was released either, and eventually became usable. D2007 is way better than D2005 &#8212; it&#8217;s just frustrating that some very visible issues still need to be fixed before it can actually be used in a production environment.</p>
]]></content:encoded>
			<wfw:commentRss>http://www.brandonstaggs.com/2007/03/27/delphi-2007-oops-earlier-this-month-i-blogged/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>Delphi 2007 for Win32 Field Test</title>
		<link>http://www.brandonstaggs.com/2007/03/13/delphi-2007-for-win32-field-test/</link>
		<comments>http://www.brandonstaggs.com/2007/03/13/delphi-2007-for-win32-field-test/#comments</comments>
		<pubDate>Tue, 13 Mar 2007 07:15:00 +0000</pubDate>
		<dc:creator>Brandon</dc:creator>
				<category><![CDATA[Software & Technology]]></category>
		<category><![CDATA[delphi]]></category>

		<guid isPermaLink="false">http://www.brandonstaggs.com/wptest/?p=296</guid>
		<description><![CDATA[CodeGear is great.
Back when Borland tried to sell off the developer tools group of their company, I received a few emails from people who know I use Delphi warning me that I need to switch to something else. I wasn&#8217;t too worried then, and I am not worried at all about it now. Borland couldn&#8217;t [...]]]></description>
			<content:encoded><![CDATA[<p><a target="_blank" href="http://www.codegear.com/">CodeGear</a> is great.</p>
<p>Back when Borland tried to sell off the developer tools group of their company, I received a few emails from people who know I use Delphi warning me that I need to switch to something else. I wasn&#8217;t too worried then, and I am not worried at all about it now. Borland couldn&#8217;t find a buyer, so they spun off the tools group into CodeGear, and CodeGear is different.</p>
<p>For the past month I&#8217;ve been beta testing the next release of Delphi &#8212; <a target="_blank" href="http://www.codegear.com/Products/Delphi/Delphi2007forWin32/tabid/236/Default.aspx">Delphi 2007 for Win32</a>. Though I had to sign a nondisclosure agreement to participate in the beta testing, CodeGear has given me permission to talk about it now.</p>
<p>Delphi 2007 for Win32 is great &#8212; it&#8217;s exactly what I was hoping for in the next Delphi. I don&#8217;t have a lot to add that hasn&#8217;t already been blogged about by others, but I do want to give my kudos to Nick Hodges and the rest of the CodeGear team. They listened! Lots of us were screaming at Borland that their focus needed to be changed to get a Windows Vista development tool out sooner rather than later &#8212; rather than focusing on .Net first. And so they are. Delphi 2007 for Win32 is just what I need, as a Windows application developer who is not yet interested in .Net. This is Delphi&#8217;s strength, and I am glad to see CodeGear getting this taken cared of first.</p>
]]></content:encoded>
			<wfw:commentRss>http://www.brandonstaggs.com/2007/03/13/delphi-2007-for-win32-field-test/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>Turbo Tools has a website</title>
		<link>http://www.brandonstaggs.com/2006/08/08/turbo-tools-has-a-website/</link>
		<comments>http://www.brandonstaggs.com/2006/08/08/turbo-tools-has-a-website/#comments</comments>
		<pubDate>Tue, 08 Aug 2006 16:57:00 +0000</pubDate>
		<dc:creator>Brandon</dc:creator>
				<category><![CDATA[Software & Technology]]></category>
		<category><![CDATA[delphi]]></category>

		<guid isPermaLink="false">http://www.brandonstaggs.com/wptest/?p=283</guid>
		<description><![CDATA[Here&#8217;s a little update on yesterday&#8217;s blog post: The &#8220;Turbo Tools&#8221; has a website.
]]></description>
			<content:encoded><![CDATA[<p>Here&#8217;s a little update on yesterday&#8217;s blog post: The <a target="_blank" href="http://www.turboexplorer.com/">&#8220;Turbo Tools&#8221; has a website</a>.</p>
]]></content:encoded>
			<wfw:commentRss>http://www.brandonstaggs.com/2006/08/08/turbo-tools-has-a-website/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>Borland brings back Turbo development tools</title>
		<link>http://www.brandonstaggs.com/2006/08/07/borland-brings-back-turbo-development-tools/</link>
		<comments>http://www.brandonstaggs.com/2006/08/07/borland-brings-back-turbo-development-tools/#comments</comments>
		<pubDate>Mon, 07 Aug 2006 23:39:00 +0000</pubDate>
		<dc:creator>Brandon</dc:creator>
				<category><![CDATA[Software & Technology]]></category>
		<category><![CDATA[delphi]]></category>

		<guid isPermaLink="false">http://www.brandonstaggs.com/wptest/?p=282</guid>
		<description><![CDATA[Good news on the Delphi front: Borland brings back its Turbo Tools.
I&#8217;ve been a loyal Borland tools user for as long as I have been seriously programming. I cut my teeth on Turbo Pascal. I taught myself C with Borland C++ when it was still a DOS-only tool. I programmed SwordSearcher 2.0 with Borland C++ [...]]]></description>
			<content:encoded><![CDATA[<p>Good news on the Delphi front: <a target="_blank" href="http://www.eweek.com/article2/0,1895,2000205,00.asp">Borland brings back its Turbo Tools</a>.</p>
<p>I&#8217;ve been a loyal Borland tools user for as long as I have been seriously programming. I cut my teeth on <a target="_blank" href="http://en.wikipedia.org/wiki/Turbo_Pascal">Turbo Pascal</a>. I taught myself C with Borland C++ when it was still a DOS-only tool. I programmed SwordSearcher 2.0 with Borland C++ 4, SwordSearcher 3.0 with Borland C++ 5, and <a href="http://www.swordsearcher.com">SwordSearcher 4</a> with Delphi 5, 6, 7, 2005, and 2006.</p>
<p>Borland&#8217;s early strength, in my view, was its affordable and powerful tools targeted at students and independent developers. They&#8217;ve been spending a lot of time, research, and money developing for the &#8220;enterprise sector,&#8221; which I know has a lot of money in it –- but they&#8217;ve lost sight the early developer who wants a platform to code for fun, or as a hobby, or as an independent software vendor. As a result of this, they&#8217;ve lost a lot of &#8220;new blood&#8221; with people going for the free (but not very good) tools, or for the inexpensive Microsoft &#8220;lite&#8221; platforms.</p>
<p>This is just my opinion, of course. I&#8217;ve not looked to research to back up this particular gut estimation of the current state of development tools. But it is where I bring home my bacon, so I think I have some grasp of the situation.</p>
<p>Finally, Borland (or, more likely, the Developer Tools guys at Borland) is doing something to make an effort to get new developers into their camp. Good! I&#8217;ve been using Delphi for years. Delphi Developer Studio 2006 is the best Win32 development platform available, period. I want Delphi to prosper so that I can continue using it!</p>
<p>Hopefully this will make Borland&#8217;s divestiture of the Devloper Tools group more successful. My read on the DevCo guys (as they are calling themselves) is that they can&#8217;t wait to get out from under Borland, which is more focused on management buzzword-ware &#8220;application lifecycle management&#8221; stuff –- whatever -– than it is on making good development tools. I am looking forward to an unhindered Delphi development team churning out the best IDE for Windows programmers for years to come.</p>
]]></content:encoded>
			<wfw:commentRss>http://www.brandonstaggs.com/2006/08/07/borland-brings-back-turbo-development-tools/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>Delphi 2006 is wonderful.</title>
		<link>http://www.brandonstaggs.com/2005/12/19/delphi-2006-is-wonderful/</link>
		<comments>http://www.brandonstaggs.com/2005/12/19/delphi-2006-is-wonderful/#comments</comments>
		<pubDate>Mon, 19 Dec 2005 22:48:00 +0000</pubDate>
		<dc:creator>Brandon</dc:creator>
				<category><![CDATA[Software & Technology]]></category>
		<category><![CDATA[delphi]]></category>
		<category><![CDATA[tech]]></category>

		<guid isPermaLink="false">http://www.brandonstaggs.com/wptest/?p=270</guid>
		<description><![CDATA[Delphi 2006 is wonderful.
Really, it is. Borland has fully redeemed themselves for the less-than-stellar Delphi 2005. After the third update and some unofficial patches, Delphi 2005 was okay (and indeed I was using it regularly and enjoyed it)&#8230; but
Delphi 2006 is wonderful!
It&#8217;s stable and has lots of great features to make a programmer more productive. [...]]]></description>
			<content:encoded><![CDATA[<p><a href="http://www.borland.com/us/products/delphi/index.html">Delphi</a> 2006 is wonderful.</p>
<p>Really, it is. Borland has fully redeemed themselves for the less-than-stellar Delphi 2005. After the third update and some unofficial patches, Delphi 2005 was okay (and indeed I was using it regularly and enjoyed it)&#8230; but</p>
<p>Delphi 2006 is wonderful!</p>
<p>It&#8217;s stable and has lots of great features to make a programmer more productive. There&#8217;s not much more I can say about it &#8212; I just like it!</p>
<p>I&#8217;m working on the next version of <a href="http://www.dailybibleandprayer.com">Daily Bible and Prayer</a> and my usual semi-annual update of <a href="http://www.swordsearcher.com">SwordSearcher</a>, and I am just as happy as I can be using Delphi 2006 for the work.</p>
<p>One great bonus for users of my software: Delphi 2006 has a more efficient memory manager, so compiled applications actually run faster. I&#8217;m looking forward to the new releases.</p>
<p>(Oh, and I haven&#8217;t blogged much recently because I&#8217;ve been busy programming!)</p>
]]></content:encoded>
			<wfw:commentRss>http://www.brandonstaggs.com/2005/12/19/delphi-2006-is-wonderful/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
	</channel>
</rss>
