<?xml version='1.0' encoding='UTF-8'?><?xml-stylesheet href="http://www.blogger.com/styles/atom.css" type="text/css"?><feed xmlns='http://www.w3.org/2005/Atom' xmlns:openSearch='http://a9.com/-/spec/opensearchrss/1.0/' xmlns:georss='http://www.georss.org/georss' xmlns:gd='http://schemas.google.com/g/2005' xmlns:thr='http://purl.org/syndication/thread/1.0'><id>tag:blogger.com,1999:blog-6458454884392032777</id><updated>2011-12-09T12:53:48.499-08:00</updated><title type='text'>Ruminated Rumblings</title><subtitle type='html'>A blog about coding, CodeGear's Delphi product, and whatever else strikes my fancy</subtitle><link rel='http://schemas.google.com/g/2005#feed' type='application/atom+xml' href='http://ruminatedrumblings.blogspot.com/feeds/posts/default'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/6458454884392032777/posts/default?max-results=100'/><link rel='alternate' type='text/html' href='http://ruminatedrumblings.blogspot.com/'/><link rel='hub' href='http://pubsubhubbub.appspot.com/'/><author><name>Marshall Fryman</name><uri>http://www.blogger.com/profile/02996248168525053524</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><generator version='7.00' uri='http://www.blogger.com'>Blogger</generator><openSearch:totalResults>20</openSearch:totalResults><openSearch:startIndex>1</openSearch:startIndex><openSearch:itemsPerPage>100</openSearch:itemsPerPage><entry><id>tag:blogger.com,1999:blog-6458454884392032777.post-4769586536710862256</id><published>2009-11-10T17:08:00.000-08:00</published><updated>2009-11-11T11:04:46.376-08:00</updated><title type='text'>Call for Delphi Developers</title><content type='html'>My company is looking for a few good developers for some Delphi contract work. Are you (or someone you know) looking for a bit of work and fit one of the profiles below? If so, drop me a line at marshall dot fryman at gmail dot com. I'm looking for experienced Delphi developers only. You'll need references and samples. We only speak English so you will need to be reasonably conversant with it.&lt;br /&gt;&lt;br /&gt;Digital Metaphors ReportBuilder specialist - We need over a hundred reports written. The reports are financially-oriented. We'll be doing Balance Sheet, Sales Summaries, Reorder Reports, etc. The focus here is mostly on the report writing and less on configuring the underlying RB engine. You'll need to be familiar with GL systems and accounting reports.&lt;br /&gt;&lt;br /&gt;RemObjects specialist - I need someone who is very familiar with RemObjects SDK. We have the licenses but have run out of resources in the short-term so we're looking to contract a new 3-tier system based on the SDK. In our case, we will have a client, local server, and remote server (remote read as "over the Internet"). We will transfer data, configuration information and command-and-control requests over this conduit. We will also utilize Hydra on the local server to provide for plug-in extensions.&lt;br /&gt;&lt;br /&gt;Accounting Integration - I am looking for an accounting developer who has experience in working with both the Sage SDK and the QB SDK to transfer accounting data from an external application to either Sage or QB products. We already have a full GL, we just need to push it to the appropriate accounting target.&lt;br /&gt;&lt;br /&gt;Thanks in advance for any and all interest.&lt;br /&gt;&lt;br /&gt;Clarification:&lt;br /&gt;I have offices in Clearwater, FL and Anaheim, CA. There is no pressing need for you to be located near either of these sites. Remote workers are fine. My concern is the quality of the work not the location of the worker. I should also be clear I'm looking for contract workers at present. I may hire developers permanently mid-next year and would certainly discuss any opportunities with people I've contracted with before doing a general search.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/6458454884392032777-4769586536710862256?l=ruminatedrumblings.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://ruminatedrumblings.blogspot.com/feeds/4769586536710862256/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=6458454884392032777&amp;postID=4769586536710862256' title='4 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/6458454884392032777/posts/default/4769586536710862256'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/6458454884392032777/posts/default/4769586536710862256'/><link rel='alternate' type='text/html' href='http://ruminatedrumblings.blogspot.com/2009/11/call-for-delphi-developers.html' title='Call for Delphi Developers'/><author><name>Marshall Fryman</name><uri>http://www.blogger.com/profile/02996248168525053524</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>4</thr:total></entry><entry><id>tag:blogger.com,1999:blog-6458454884392032777.post-3870597203716523675</id><published>2009-07-31T10:31:00.000-07:00</published><updated>2009-07-31T10:38:37.547-07:00</updated><title type='text'>D2007 and large text files</title><content type='html'>Has anyone noticed that Delphi 2007 cannot append to a text file over 2GB in size? I freely admit that I had a problem in my code that created log files that large in the first place... but I also don't expect my compiler to blow up when dealing with files of any size. &lt;br /&gt;&lt;br /&gt;My first warning was when the append command started throwing I/O Error 131 messages. Error 131 is negative seek. The only way that could be is if CG has a signed int32 it's using for the filesize. When I hit the upper bounds of int32, it just wraps around to a negative number.&lt;br /&gt;&lt;br /&gt;In my case, I just fixed the bug and stopped making huge text files. Otherwise, it looks like I'd have to change how the append function works in the System library. Does anyone know if D2009 also has this problem?&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/6458454884392032777-3870597203716523675?l=ruminatedrumblings.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://ruminatedrumblings.blogspot.com/feeds/3870597203716523675/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=6458454884392032777&amp;postID=3870597203716523675' title='6 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/6458454884392032777/posts/default/3870597203716523675'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/6458454884392032777/posts/default/3870597203716523675'/><link rel='alternate' type='text/html' href='http://ruminatedrumblings.blogspot.com/2009/07/d2007-and-large-text-files.html' title='D2007 and large text files'/><author><name>Marshall Fryman</name><uri>http://www.blogger.com/profile/02996248168525053524</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>6</thr:total></entry><entry><id>tag:blogger.com,1999:blog-6458454884392032777.post-5887423671726844595</id><published>2009-07-30T18:31:00.000-07:00</published><updated>2009-07-30T18:52:06.081-07:00</updated><title type='text'>Gmail, POP3 and Indy</title><content type='html'>In my ever expanding need for dealing with the outside world, I've discovered a quirky little thing about Indy 10. When using the TIdPOP3 component with Gmail, you have to manually call DisconnectNotifyPeer or delete commands are ignored. I suppose this isn't quirky as much as not really documented any place I was able to find. Let's backup and start at the beginning, shall we?&lt;br /&gt;&lt;br /&gt;I have a Windows service that polls a POP3 account looking for messages that it can import into a DB. It has all sorts of fun rules that can be assigned to discover what needs to be imported, what database it goes into, etc. At any rate, this code has been merrily chugging away on both Yahoo and SmarterMail servers with nary a hiccup. I recently needed to watch a Google domain app e-mail address and didn't think much of it.&lt;br /&gt;&lt;br /&gt;Of course, in order to do so you have to implement SSL for POP3. As I've posted in the past, this is not really much of an issue, you simply create the TIdSSLIOHandlerSocketOpenSSL object and assigned it to the IOHandler like so:&lt;br /&gt;&lt;blockquote&gt;       Pop3Srv.IOHandler := TIdSSLIOHandlerSocketOpenSSL.Create(Pop3Srv);   &lt;br /&gt;     Pop3Srv.UseTLS := utUseImplicitTLS; &lt;/blockquote&gt;&lt;br /&gt;&lt;br /&gt;Anyway, all was proceeding swimmingly until I retrieved the first message. In my case, I automatically delete any e-mail that matches my rules so it will not be imported a second time. This works fine with Yahoo and SmarterMail. You just call DeleteMessage(msgNumber) and voila, away it goes. With Gmail, no such luck.&lt;br /&gt;&lt;br /&gt;Gmail actually has a three different settings under POP3. One keeps messages in the inbox after reading via POP, one archives it and one deletes it. Thinking this option was set wrong, I tried all three options... repeatedly... still no luck. I tried searching pretty extensively on this one and finally found the clue with &lt;a href="http://www.ietf.org/rfc/rfc1939.txt"&gt;RFC 1939&lt;/a&gt;. Gmail honors the "you must notify me you are quitting or I will not delete anything" rule that 1939 dictates.&lt;br /&gt;&lt;blockquote&gt;When the client issues the QUIT command from the TRANSACTION state, the POP3 session enters the UPDATE state. (Note that if the client issues the QUIT command from the AUTHORIZATION state, the POP3 session terminates but does NOT enter the UPDATE state.) If a session terminates for some reason other than a client-issued QUIT command, the POP3 session does NOT enter the UPDATE state and MUST not remove any messages from the maildrop. &lt;/blockquote&gt;&lt;br /&gt;&lt;br /&gt;After checking the code for the IdPOP3, it turns out calling Free does not issue the QUIT command. It makes sense for it not to do so. What if you wanted to avoid the UPDATE state? It was just surprising that some mail servers worked without this command and some required it.&lt;br /&gt;&lt;br /&gt;At any rate, I hope this helps someone else who's working with POP3 commands.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/6458454884392032777-5887423671726844595?l=ruminatedrumblings.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://ruminatedrumblings.blogspot.com/feeds/5887423671726844595/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=6458454884392032777&amp;postID=5887423671726844595' title='3 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/6458454884392032777/posts/default/5887423671726844595'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/6458454884392032777/posts/default/5887423671726844595'/><link rel='alternate' type='text/html' href='http://ruminatedrumblings.blogspot.com/2009/07/gmail-pop3-and-indy.html' title='Gmail, POP3 and Indy'/><author><name>Marshall Fryman</name><uri>http://www.blogger.com/profile/02996248168525053524</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>3</thr:total></entry><entry><id>tag:blogger.com,1999:blog-6458454884392032777.post-2442298507407988235</id><published>2009-04-17T16:08:00.000-07:00</published><updated>2009-04-27T10:12:01.264-07:00</updated><title type='text'>RAID, files and cloud storage</title><content type='html'>RAID is a method that takes independent drives and lets a system group them together for security (redundancy or parity), speed enhancements, storage space increases or all three. One of the long-time stalwarts of the RAID environment is RAID 5. In RAID 5, you need at least 3 identically sized disks. They are combined so that the storage space is N-1 (i.e., in a 3-drive system, total space is 2x drive size). The last disk is used for parity. With a parity drive, you can remove any &lt;span style="font-weight:bold;"&gt;one&lt;/span&gt; of the drives and still have access to your data. If you remove two or more of the drives though, you'd better have a good backup.&lt;br /&gt;&lt;br /&gt;How does this work? Through the magic of XOR. The following statements are all true:&lt;br /&gt;&lt;PRE&gt;&lt;br /&gt;A   XOR B   = PAR&lt;br /&gt;PAR XOR B   = A&lt;br /&gt;A   XOR PAR = B&lt;br /&gt;&lt;/PRE&gt;&lt;br /&gt;&lt;br /&gt;That's how parity lets you lose one disk and still recover your data. The same rules also apply in larger sets. Notice that you have to rotate the position of the parity data though. So a 5 drive system looks like:&lt;br /&gt;&lt;PRE&gt;&lt;br /&gt;A   XOR B   XOR C   XOR D   XOR E   = PAR&lt;br /&gt;PAR XOR B   XOR C   XOR D   XOR E   = A&lt;br /&gt;A   XOR PAR XOR C   XOR D   XOR E   = B&lt;br /&gt;A   XOR B   XOR PAR XOR D   XOR E   = C&lt;br /&gt;A   XOR B   XOR C   XOR PAR XOR E   = D&lt;br /&gt;A   XOR B   XOR C   XOR D   XOR PAR = E&lt;br /&gt;&lt;/PRE&gt;&lt;br /&gt;&lt;br /&gt;The other interesting thing to note is that the size stored on each drive is 1/(n-1) of the total file size. Thus a 100 byte file in a RAID 5 system only stores 20 bytes on each drive. This is where the space increase comes from.&lt;br /&gt;&lt;br /&gt;Now, the question is, why do we care? Other than it's nice to know how something works, this technique could be applied to cloud storage. If you follow some of the events that have happened with online storage providers, you may have seen a number of them come and go. The problem is, if they disappear or lose your data, what happens then? &lt;br /&gt;&lt;br /&gt;If you are using them as a convenient off-site data storage pool for large amounts of infrequently used data, you could implement a RAID 5-style data split. Keep in mind there's a bit of overhead in doing so, but the point of this exercise is to reduce your dependence on any one provider. Coincidentally, it will likely cost you the same or less than using a single cloud storage provider.&lt;br /&gt;&lt;br /&gt;Take for instance Amazon's S3 service and Rackspace's Mosso Cloud Files. Both services charge per gigabyte per month. For arguments sake, let's assume we have a 10GB RAR file (BIGFILE.RAR) that we want to backup. If we split it into a RAID 5, 3 drive format, that would leave us with BIGFILE.RAR.1, BIGFILE.RAR.2 and BIGFILE.RAR.RAID. Each file will be 5GB (10GB / (3-1)) in size. I can upload one file to Amazon, one file to Rackspace and retain one file on my hard drive. I've now backed up the file in an online form that can be recovered even if I lose my hard drive or Amazon / Rackspace has an outage at the same moment I need to have access to my data. So long as I have access to any two parts of the file, I can create the original output file.&lt;br /&gt;&lt;br /&gt;Obviously, Amazon and Rackspace are large enough it is unlikely they'd actually lose the data over a longer period of time. The same can't be said of some the smaller players in the market. Companies like Streamload managed to wipe out about half of their customers data during a reorganization before finally closing their doors. Anyone caught unaware lost all of their data.&lt;br /&gt;&lt;br /&gt;I should also note that you could use a PAR or PAR2 system. The easiest to use implementation is probably QuickPAR. It uses a similar system to what I've shown here but the source is not very conducive to Delphi developers. From what I can tell, it was originally developed to push binary files around Usenet, but it would work equally well for cloud storage. If you're just looking for a good off-the-shelf tool, QuickPAR is probably the way to go. If you're interested in developing a parity solution that you can embed in your code, the source is included below.&lt;br /&gt;&lt;br /&gt;&lt;!-- code formatted by http://manoli.net/csharpformat/ --&gt;&lt;br /&gt;&lt;pre class="csharpcode"&gt;&lt;br /&gt;procedure File2RaidFiles(fileName:&lt;span class="kwrd"&gt;string&lt;/span&gt;; raidLength:integer);&lt;br /&gt;var FS:TFileStream;&lt;br /&gt;    outputFS:array of TFileStream;&lt;br /&gt;    byteArray:array of &lt;span class="kwrd"&gt;byte&lt;/span&gt;;&lt;br /&gt;    ix:integer;&lt;br /&gt;begin&lt;br /&gt;&lt;span class="rem"&gt;//test to make sure we were called correctly&lt;/span&gt;&lt;br /&gt;&lt;span class="kwrd"&gt;if&lt;/span&gt; not FileExists(fileName) then&lt;br /&gt;   raise Exception.Create(Format(&lt;span class="str"&gt;'File %s doesn'&lt;/span&gt;&lt;span class="str"&gt;'t exist'&lt;/span&gt;, [fileName]));&lt;br /&gt;&lt;span class="kwrd"&gt;if&lt;/span&gt; raidLength&amp;lt;2 then&lt;br /&gt;   raise Exception.Create(Format(&lt;span class="str"&gt;'Raid Length must be greater than 1. Given value was %d'&lt;/span&gt;,[raidLength]));&lt;br /&gt;&lt;br /&gt;FS:=TFileStream.Create(fileName,fmOpenRead);&lt;br /&gt;&lt;span class="kwrd"&gt;try&lt;/span&gt;&lt;br /&gt;   setLength(outputFS, raidLength+1); &lt;span class="rem"&gt;//+1 for the parity byte&lt;/span&gt;&lt;br /&gt;   setLength(byteArray, raidLength+1);&lt;br /&gt;   &lt;span class="kwrd"&gt;for&lt;/span&gt; ix := 0 to raidLength &lt;span class="kwrd"&gt;do&lt;/span&gt;       &lt;span class="rem"&gt;//create an output location for each stripe (named .stripe#) and the parity file (named .raid)&lt;/span&gt;&lt;br /&gt;      begin&lt;br /&gt;      &lt;span class="kwrd"&gt;if&lt;/span&gt; ix=raidLength then&lt;br /&gt;         outputFS[ix]:=TFileStream.Create(fileName+&lt;span class="str"&gt;'.raid'&lt;/span&gt;,fmCreate)&lt;br /&gt;      &lt;span class="kwrd"&gt;else&lt;/span&gt;&lt;br /&gt;         outputFS[ix]:=TFileStream.Create(fileName+&lt;span class="str"&gt;'.'&lt;/span&gt;+IntToStr(ix),fmCreate);&lt;br /&gt;      end;&lt;br /&gt;   &lt;span class="kwrd"&gt;try&lt;/span&gt;&lt;br /&gt;      &lt;span class="kwrd"&gt;while&lt;/span&gt; FS.Position&amp;lt;FS.Size &lt;span class="kwrd"&gt;do&lt;/span&gt;                         &lt;span class="rem"&gt;//while we haven't hit the end of the file&lt;/span&gt;&lt;br /&gt;         begin&lt;br /&gt;         FS.Read(byteArray[0],raidLength);                 &lt;span class="rem"&gt;//read in the bytes to the byteArray&lt;/span&gt;&lt;br /&gt;         &lt;span class="kwrd"&gt;for&lt;/span&gt; ix := 0 to raidLength-2 &lt;span class="kwrd"&gt;do&lt;/span&gt;                    &lt;span class="rem"&gt;//this calcs the parity byte, it's calculated by XORing the other bytes to it&lt;/span&gt;&lt;br /&gt;            byteArray[raidLength]:=byteArray[ix] xor byteArray[ix+1];&lt;br /&gt;         &lt;span class="kwrd"&gt;for&lt;/span&gt; ix := 0 to raidLength &lt;span class="kwrd"&gt;do&lt;/span&gt;                      &lt;span class="rem"&gt;//write out the bytes to the respective stripes (stripes are &amp;lt; raidlength) and the parity file (outputFS[raidlength])&lt;/span&gt;&lt;br /&gt;            outputFS[ix].Write(byteArray[ix],1);&lt;br /&gt;         end;&lt;br /&gt;   &lt;span class="kwrd"&gt;finally&lt;/span&gt;&lt;br /&gt;      &lt;span class="kwrd"&gt;for&lt;/span&gt; ix := 0 to raidLength &lt;span class="kwrd"&gt;do&lt;/span&gt;                         &lt;span class="rem"&gt;//clean up the output streams&lt;/span&gt;&lt;br /&gt;         outputFS[ix].Free;&lt;br /&gt;   end;&lt;br /&gt;&lt;span class="kwrd"&gt;finally&lt;/span&gt;&lt;br /&gt;   FS.Free;                                                &lt;span class="rem"&gt;//clean up the input stream&lt;/span&gt;&lt;br /&gt;end;&lt;br /&gt;end;&lt;br /&gt;&lt;br /&gt;procedure RaidFiles2File(fileName, outputName:&lt;span class="kwrd"&gt;string&lt;/span&gt;; raidLength:integer);&lt;br /&gt;var FS:TFileStream;&lt;br /&gt;    inputFS:array of TFileStream;&lt;br /&gt;    testFS:TFileStream;&lt;br /&gt;    byteArray:array of &lt;span class="kwrd"&gt;byte&lt;/span&gt;;&lt;br /&gt;    ix, damage:integer;&lt;br /&gt;    countOfMissing:integer;&lt;br /&gt;    checkByte:&lt;span class="kwrd"&gt;byte&lt;/span&gt;;&lt;br /&gt;    checkFails:boolean;&lt;br /&gt;begin&lt;br /&gt;&lt;span class="rem"&gt;//test to make sure we were called correctly&lt;/span&gt;&lt;br /&gt;&lt;span class="kwrd"&gt;if&lt;/span&gt; FileExists(outputName) then&lt;br /&gt;   raise Exception.Create(Format(&lt;span class="str"&gt;'File %s already exist'&lt;/span&gt;, [outputName]));&lt;br /&gt;&lt;span class="kwrd"&gt;if&lt;/span&gt; raidLength&amp;lt;2 then&lt;br /&gt;   raise Exception.Create(Format(&lt;span class="str"&gt;'Raid Length must be greater than 1. Given value was %d'&lt;/span&gt;,[raidLength]));&lt;br /&gt;&lt;span class="rem"&gt;//init the basics&lt;/span&gt;&lt;br /&gt;checkFails:=&lt;span class="kwrd"&gt;false&lt;/span&gt;;&lt;br /&gt;testFS:=nil;&lt;br /&gt;countOfMissing:=0;&lt;br /&gt;damage:=0;&lt;br /&gt;setLength(inputFS, raidLength+1); &lt;span class="rem"&gt;//+1 is the parity byte&lt;/span&gt;&lt;br /&gt;setLength(byteArray, raidLength+1);&lt;br /&gt;&lt;span class="kwrd"&gt;for&lt;/span&gt; ix := 0 to raidLength &lt;span class="kwrd"&gt;do&lt;/span&gt;&lt;br /&gt;   inputFS[ix]:=nil;&lt;br /&gt;&lt;br /&gt;&lt;span class="rem"&gt;//setup the output file stream&lt;/span&gt;&lt;br /&gt;FS:=TFileStream.Create(outputName,fmCreate);&lt;br /&gt;&lt;span class="kwrd"&gt;try&lt;/span&gt;&lt;br /&gt;   &lt;span class="rem"&gt;//create the input file streams. make sure we pickup the count of missing streams and a pntr to an input stream for use later on (any stream will do, just testing for eof&lt;/span&gt;&lt;br /&gt;   &lt;span class="kwrd"&gt;for&lt;/span&gt; ix := 0 to raidLength &lt;span class="kwrd"&gt;do&lt;/span&gt;&lt;br /&gt;      begin&lt;br /&gt;      &lt;span class="kwrd"&gt;if&lt;/span&gt; ix=raidLength then &lt;span class="rem"&gt;//this is the parity stream&lt;/span&gt;&lt;br /&gt;         begin&lt;br /&gt;         &lt;span class="kwrd"&gt;if&lt;/span&gt; FileExists(fileName+&lt;span class="str"&gt;'.raid'&lt;/span&gt;) then&lt;br /&gt;            inputFS[ix]:=TFileStream.Create(fileName+&lt;span class="str"&gt;'.raid'&lt;/span&gt;,fmOpenRead)&lt;br /&gt;         end&lt;br /&gt;      &lt;span class="kwrd"&gt;else&lt;/span&gt;                  &lt;span class="rem"&gt;//this is a stripe stream&lt;/span&gt;&lt;br /&gt;         begin&lt;br /&gt;         &lt;span class="kwrd"&gt;if&lt;/span&gt; FileExists(fileName+&lt;span class="str"&gt;'.'&lt;/span&gt;+IntToStr(ix)) then&lt;br /&gt;            begin&lt;br /&gt;            inputFS[ix]:=TFileStream.Create(fileName+&lt;span class="str"&gt;'.'&lt;/span&gt;+IntToStr(ix),fmOpenRead);&lt;br /&gt;            testFS:=inputFS[ix];  &lt;span class="rem"&gt;//this is just to test for eof. all files are the same size&lt;/span&gt;&lt;br /&gt;            end;&lt;br /&gt;         end;&lt;br /&gt;      &lt;span class="kwrd"&gt;if&lt;/span&gt; inputFS[ix]=nil then inc(countOfMissing); &lt;span class="rem"&gt;//if we didn't get an input stream, add to the missing count&lt;/span&gt;&lt;br /&gt;      end;&lt;br /&gt;   &lt;span class="rem"&gt;//you are only allowed to have 1 missing input file&lt;/span&gt;&lt;br /&gt;   &lt;span class="kwrd"&gt;if&lt;/span&gt; countOfMissing&amp;gt;1 then&lt;br /&gt;      raise Exception.Create(&lt;span class="str"&gt;'Unable to recover file! You must have at least N-1 parts of the file'&lt;/span&gt;);&lt;br /&gt;   assert(testFS&amp;lt;&amp;gt;nil, &lt;span class="str"&gt;'testFS=nil? This should never happen'&lt;/span&gt;);&lt;br /&gt;&lt;br /&gt;   &lt;span class="kwrd"&gt;while&lt;/span&gt; testFS.Position&amp;lt;testFS.Size &lt;span class="kwrd"&gt;do&lt;/span&gt; &lt;span class="rem"&gt;//while we are not at the end of the input file&lt;/span&gt;&lt;br /&gt;      begin&lt;br /&gt;      &lt;span class="kwrd"&gt;if&lt;/span&gt; countOfMissing=0 then          &lt;span class="rem"&gt;//if there are no missing streams, we can just remerge the data together&lt;/span&gt;&lt;br /&gt;         begin&lt;br /&gt;         &lt;span class="kwrd"&gt;for&lt;/span&gt; ix := 0 to raidLength &lt;span class="kwrd"&gt;do&lt;/span&gt;&lt;br /&gt;            inputFS[ix].Read(byteArray[ix],1);&lt;br /&gt;&lt;br /&gt;         checkByte:=0;&lt;br /&gt;         &lt;span class="rem"&gt;//calc a checkByte to make sure it all still agrees&lt;/span&gt;&lt;br /&gt;         &lt;span class="kwrd"&gt;for&lt;/span&gt; ix := 0 to raidLength-2 &lt;span class="kwrd"&gt;do&lt;/span&gt; &lt;span class="rem"&gt;//0 based, stop 1 short of the end&lt;/span&gt;&lt;br /&gt;            &lt;span class="kwrd"&gt;if&lt;/span&gt; ix=0 then&lt;br /&gt;               checkByte:=byteArray[ix] xor byteArray[ix+1] &lt;span class="rem"&gt;//seed check byte by XORing the 1st two bytes together&lt;/span&gt;&lt;br /&gt;            &lt;span class="kwrd"&gt;else&lt;/span&gt;&lt;br /&gt;               checkByte:=checkbyte xor byteArray[ix+1];      &lt;span class="rem"&gt;//XOR the bytes together&lt;/span&gt;&lt;br /&gt;         &lt;span class="kwrd"&gt;if&lt;/span&gt; checkByte&amp;lt;&amp;gt;byteArray[raidLength] then  &lt;span class="rem"&gt;//the new checkByte doesn't match the old parity byte. That means we have a problem, the file doesn't match&lt;/span&gt;&lt;br /&gt;            checkFails:=&lt;span class="kwrd"&gt;true&lt;/span&gt;;&lt;br /&gt;         end&lt;br /&gt;      &lt;span class="kwrd"&gt;else&lt;/span&gt;                              &lt;span class="rem"&gt;//if there are missing streams, we have to calculate the missing data&lt;/span&gt;&lt;br /&gt;         begin                          &lt;span class="rem"&gt;//you have to reverse the XOR with the parity bit to determine the result&lt;/span&gt;&lt;br /&gt;         &lt;span class="kwrd"&gt;for&lt;/span&gt; ix := 0 to raidLength-1 &lt;span class="kwrd"&gt;do&lt;/span&gt; &lt;span class="rem"&gt;//not counting the end of the array, that's where we'll store the damaged byte&lt;/span&gt;&lt;br /&gt;            &lt;span class="kwrd"&gt;if&lt;/span&gt; inputFS[ix]&amp;lt;&amp;gt;nil then    &lt;span class="rem"&gt;//if this is a valid stream, read it's data&lt;/span&gt;&lt;br /&gt;               inputFS[ix].Read(byteArray[ix],1)&lt;br /&gt;            &lt;span class="kwrd"&gt;else&lt;/span&gt;&lt;br /&gt;               begin                    &lt;span class="rem"&gt;//this isn't a valid stream, so remember this is damaged and read from the parity stream for this position&lt;/span&gt;&lt;br /&gt;               damage:=ix;&lt;br /&gt;               inputFS[raidLength].Read(byteArray[ix],1);&lt;br /&gt;               end;&lt;br /&gt;         &lt;span class="rem"&gt;//this is calcs the damaged byte into the end of the array (raidLength)&lt;/span&gt;&lt;br /&gt;         &lt;span class="kwrd"&gt;for&lt;/span&gt; ix := 0 to raidLength-2 &lt;span class="kwrd"&gt;do&lt;/span&gt; &lt;span class="rem"&gt;//0 based, stop 1 short of the end&lt;/span&gt;&lt;br /&gt;            byteArray[raidLength]:=byteArray[ix] xor byteArray[ix+1]; &lt;span class="rem"&gt;//XOR the bytes together&lt;/span&gt;&lt;br /&gt;         byteArray[damage]:=byteArray[raidLength]; &lt;span class="rem"&gt;//replace the damaged byte with the restored byte&lt;/span&gt;&lt;br /&gt;         end;&lt;br /&gt;      FS.Write(byteArray[0],raidLength);           &lt;span class="rem"&gt;//write out the merged (and psbly restored) data&lt;/span&gt;&lt;br /&gt;      end;&lt;br /&gt;&lt;span class="kwrd"&gt;finally&lt;/span&gt;&lt;br /&gt;   &lt;span class="kwrd"&gt;for&lt;/span&gt; ix := 0 to raidLength &lt;span class="kwrd"&gt;do&lt;/span&gt;                   &lt;span class="rem"&gt;//clean up the memory from the input streams&lt;/span&gt;&lt;br /&gt;      &lt;span class="kwrd"&gt;if&lt;/span&gt; inputFS[ix]&amp;lt;&amp;gt;nil then inputFS[ix].Free;&lt;br /&gt;   FS.Free;                                       &lt;span class="rem"&gt;//clean up the memory for the output stream&lt;/span&gt;&lt;br /&gt;end;&lt;br /&gt;&lt;span class="kwrd"&gt;if&lt;/span&gt; checkFails then&lt;br /&gt;   raise Exception.Create(Format(&lt;span class="str"&gt;'This file (%s) does not match to its parity checks. Damage may be present'&lt;/span&gt;, [outputName]));&lt;br /&gt;end;&lt;br /&gt;&lt;/pre&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/6458454884392032777-2442298507407988235?l=ruminatedrumblings.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://ruminatedrumblings.blogspot.com/feeds/2442298507407988235/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=6458454884392032777&amp;postID=2442298507407988235' title='7 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/6458454884392032777/posts/default/2442298507407988235'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/6458454884392032777/posts/default/2442298507407988235'/><link rel='alternate' type='text/html' href='http://ruminatedrumblings.blogspot.com/2009/04/raid-files-and-cloud-storage.html' title='RAID, files and cloud storage'/><author><name>Marshall Fryman</name><uri>http://www.blogger.com/profile/02996248168525053524</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>7</thr:total></entry><entry><id>tag:blogger.com,1999:blog-6458454884392032777.post-4559974130440189691</id><published>2009-01-14T09:47:00.000-08:00</published><updated>2009-01-14T10:04:59.493-08:00</updated><title type='text'>Qt becomes LGPL licensed</title><content type='html'>Nokia has &lt;a href="http://www.qtsoftware.com/about/licensing"&gt;announced&lt;/a&gt; that the new Qt library (4.5) will be available under the LGPL license (March 2009). Hopefully, this will mean that Embarcadero will revive Linux support with it's upcoming 64-bit, compile-to-many-targets compiler rewrite. &lt;br /&gt;&lt;br /&gt;Actually, it could mean that we would finally have a true CLX revision that would let us have native write-once, compile-to-many-targets, cross platform support for Windows, Mac, Linux, Embedded Linux, Windows CE, and the S60 (eventually). If Delphi's component architecture could be revamped to produce true Qt widgets, Embarcadero would suddenly enable all of the Delphi component vendors to gain access to a client-base that is much larger than what Delphi currently offers. Qt does not have much selection from third-party component vendors. A DevExpress or TMS Software offering would provide a nice upgrade to the basic Qt widgets.&lt;br /&gt;&lt;br /&gt;Delphi Prism theoretically supports multi-platform through the use of Mono but you have to add the managed code overhead to everything. There was a &lt;a href="http://arstechnica.com/news.ars/post/20090108-open-source-mono-framework-brings-c-to-iphone-and-wii.html"&gt;recent article&lt;/a&gt; on using Mono to develop for the iPhone which talked about stripping the managed code down to a true compiled state (Apple doesn't permit managed code to run apparently.) It was done with C# but there is no particular reason (that I'm aware of) Delphi Prism couldn't work the same way. Has anyone tried to do multi-platform with Prism?&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/6458454884392032777-4559974130440189691?l=ruminatedrumblings.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://ruminatedrumblings.blogspot.com/feeds/4559974130440189691/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=6458454884392032777&amp;postID=4559974130440189691' title='7 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/6458454884392032777/posts/default/4559974130440189691'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/6458454884392032777/posts/default/4559974130440189691'/><link rel='alternate' type='text/html' href='http://ruminatedrumblings.blogspot.com/2009/01/qt-becomes-lgpl-licensed.html' title='Qt becomes LGPL licensed'/><author><name>Marshall Fryman</name><uri>http://www.blogger.com/profile/02996248168525053524</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>7</thr:total></entry><entry><id>tag:blogger.com,1999:blog-6458454884392032777.post-6858351949685752530</id><published>2008-11-03T14:08:00.000-08:00</published><updated>2008-11-03T15:36:40.219-08:00</updated><title type='text'>Word, WordPad and RTF</title><content type='html'>In yet another stunning victory for Microsoft's cross-compatibility, their RTF system is incompatible between their own products. Let me begin by explaining that I have a Delphi app that uses a mail merge system to merge database text into a document. Naturally, you can do this a lot of different ways but, for my particular instance, I need to merge from a non-ODBC compliant database and then automatically E-mail the resulting document to the correct person. This is a management tool we use fairly heavily.&lt;br /&gt;&lt;br /&gt;In the past, I've always just used raw HTML formatting because it's handy and relatively standard. The particular request I've been working on is to format the resulting merge so that it can be printed in a "one summary page per item" format. HTML has the ability to do this with a style sheet as such:&lt;br /&gt;&lt;br /&gt;&lt;!-- code formatted by http://manoli.net/csharpformat/ --&gt;&lt;br /&gt;&lt;pre class="csharpcode"&gt;&lt;br /&gt;&lt;span class="kwrd"&gt;&amp;lt;&lt;/span&gt;&lt;span class="html"&gt;STYLE&lt;/span&gt; &lt;span class="attr"&gt;TYPE&lt;/span&gt;&lt;span class="kwrd"&gt;="text/css"&lt;/span&gt;&lt;span class="kwrd"&gt;&amp;gt;&lt;/span&gt;&lt;br /&gt;     P.breakhere {page-break-before: always}&lt;br /&gt;&lt;span class="kwrd"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="html"&gt;STYLE&lt;/span&gt;&lt;span class="kwrd"&gt;&amp;gt;&lt;/span&gt; &lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;and use it via:&lt;br /&gt;&lt;br /&gt;&lt;!-- code formatted by http://manoli.net/csharpformat/ --&gt;&lt;br /&gt;&lt;pre class="csharpcode"&gt;&lt;br /&gt;&lt;span class="kwrd"&gt;&amp;lt;&lt;/span&gt;&lt;span class="html"&gt;p&lt;/span&gt; &lt;span class="attr"&gt;class&lt;/span&gt;&lt;span class="kwrd"&gt;="breakhere"&lt;/span&gt;&lt;span class="kwrd"&gt;&amp;gt;&lt;/span&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;Thanks to &lt;a href="http://www.htmlgoodies.com/beyond/css/article.php/3470341"&gt;HTML Goodies&lt;/a&gt; for the information.&lt;br /&gt;&lt;br /&gt;Now, the downside to this is that HTML print formatting appears to be considered optional by... well... everyone. I initially sent the HTML to my Gmail account. It appears fine but without the page breaks. I would expect this considering Gmail has it's own HTML enclosure. I would not expect the PRINT to ignore all of the HTML formatting, but it does. I suppose this makes some sense in light of the header information they put at the top of the output. The process of placing the header must remove the rest of the print formatting. Keep in mind this is the equivalent of an HTML E-mail, not an HTML attachment. When I converted over to an HTML attachment, Gmail dutifully opens the attachment and FF3 prints the document out just fine.&lt;br /&gt;&lt;br /&gt;On to Outlook. One would think that Outlook should honor HTML formatting since, unlike Gmail, it doesn't actually use any HTML for display or printing. This is not so. HTML prints from Outlook without the page breaks from the normal reader pane. Thinking I could force the issue, I dbl-clicked the message in Outlook (which of course puts it in Word) and voila - no difference. This is turning into a major hassle. Additionally, because Outlook is so clever, it won't really let you send an HTML attachment. Instead, it displays it in-line with the same problems printing as with an HTML E-mail.&lt;br /&gt;&lt;br /&gt;On to the solution... &lt;br /&gt;&lt;br /&gt;I had to select some format other than HTML but it must be 7-bit text-based because of the way my Delphi merge app works. That pretty much leaves me with PDF or RTF as easy standards that everyone can open. I settled on RTF because it's easy to create an RTF file in OpenOffice, save it out and hack it apart with &lt;a href="http://www.semware.com"&gt;TSE Pro&lt;/a&gt;. My merge codes are just enclosed in &lt;&lt; &gt;&gt; (ala MS Word style) so a name would be &lt;!-- code formatted by http://manoli.net/csharpformat/ --&gt;&lt;br /&gt;&lt;pre class="csharpcode"&gt;&lt;br /&gt;&lt;span class="kwrd"&gt;&amp;lt;&amp;lt;&lt;/span&gt;&lt;span class="html"&gt;name&lt;/span&gt;&lt;span class="kwrd"&gt;&amp;gt;&amp;gt;&lt;/span&gt;&lt;/pre&gt;. Anyway, this all works, although I don't really recommend reading RTF as a form of entertainment. Many trial and error attempts later I had a document that works fine in WordPad and OpenOffice. It just won't work in Word.&lt;br /&gt;&lt;br /&gt;This is not to say that Word doesn't open the document. It does, it just ignores the page breaks. I tried the same RTF file in Word 07 and Word 03 with the same results. Even more annoying, if I open the file in WordPad and then save it back out as RTF, Word still won't have the page breaks. After reading the RTF documentation, I was left with the impression that \page should always generate a new page. It turns out that Word won't take just a \page like the documentation, WordPad and OpenOffice. It HAS to be "\par \page \par " and please don't forget the ending space. In Word, this works fine. In WordPad and OO, it generates a leading blank line. In my case, I can call this close enough sine the summary pages are so short anyway. If I was pressed for space though, it would be an issue that would probably force me to PDF. &lt;br /&gt;&lt;br /&gt;In another quirky little thing, when I created my file in OO and saved it out as RTF, my file size was 38k. If I open the file in WordPad and save it out, it shrinks to 13k. If I open the original in Word 07 and save it out, it grows to 87k. How can the same RTF encoding size vary that much from the same company? Even more annoying, why aren't WordPad and Word interoperable using RTF?&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/6458454884392032777-6858351949685752530?l=ruminatedrumblings.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://ruminatedrumblings.blogspot.com/feeds/6858351949685752530/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=6458454884392032777&amp;postID=6858351949685752530' title='4 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/6458454884392032777/posts/default/6858351949685752530'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/6458454884392032777/posts/default/6858351949685752530'/><link rel='alternate' type='text/html' href='http://ruminatedrumblings.blogspot.com/2008/11/word-wordpad-and-rtf.html' title='Word, WordPad and RTF'/><author><name>Marshall Fryman</name><uri>http://www.blogger.com/profile/02996248168525053524</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>4</thr:total></entry><entry><id>tag:blogger.com,1999:blog-6458454884392032777.post-9085429063360370536</id><published>2008-08-15T15:32:00.000-07:00</published><updated>2008-08-15T16:16:52.374-07:00</updated><title type='text'>MapQuest and Delphi</title><content type='html'>A few weeks ago I started down the path of discovering how to GeoCode addresses for Delphi. This is related to a project we had where we wanted to show a map of a given point and then show facilities located near it on a map. I had originally started working with maps.live.com (which is a MS site). They have a decent little interface for JS that seemed to work for what I wanted AND I didn't have to store the annoying little GeoCoding addresses anywhere. This works great if all you want is a single address. For instance, the code below works for single addresses:&lt;br /&gt;&lt;br /&gt;&lt;!-- code formatted by http://manoli.net/csharpformat/ --&gt;&lt;br /&gt;&lt;pre class="csharpcode"&gt;&lt;br /&gt;&lt;span class="kwrd"&gt;&amp;lt;&lt;/span&gt;&lt;span class="html"&gt;html&lt;/span&gt;&lt;span class="kwrd"&gt;&amp;gt;&lt;/span&gt;&lt;br /&gt;   &lt;span class="kwrd"&gt;&amp;lt;&lt;/span&gt;&lt;span class="html"&gt;head&lt;/span&gt;&lt;span class="kwrd"&gt;&amp;gt;&lt;/span&gt;&lt;br /&gt;      &lt;span class="kwrd"&gt;&amp;lt;&lt;/span&gt;&lt;span class="html"&gt;title&lt;/span&gt;&lt;span class="kwrd"&gt;&amp;gt;&lt;/span&gt;Address Lookup &lt;span class="kwrd"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="html"&gt;title&lt;/span&gt;&lt;span class="kwrd"&gt;&amp;gt;&lt;/span&gt;&lt;br /&gt;      &lt;span class="kwrd"&gt;&amp;lt;&lt;/span&gt;&lt;span class="html"&gt;meta&lt;/span&gt; &lt;span class="attr"&gt;http-equiv&lt;/span&gt;&lt;span class="kwrd"&gt;="Content-Type"&lt;/span&gt; &lt;span class="attr"&gt;content&lt;/span&gt;&lt;span class="kwrd"&gt;="text/html; charset=utf-8"&lt;/span&gt;&lt;span class="kwrd"&gt;&amp;gt;&lt;/span&gt;&lt;br /&gt;      &lt;span class="kwrd"&gt;&amp;lt;&lt;/span&gt;&lt;span class="html"&gt;script&lt;/span&gt; &lt;span class="attr"&gt;type&lt;/span&gt;&lt;span class="kwrd"&gt;="text/javascript"&lt;/span&gt; &lt;span class="attr"&gt;src&lt;/span&gt;&lt;span class="kwrd"&gt;="http://dev.virtualearth.net/mapcontrol/mapcontrol.ashx?v=6"&lt;/span&gt;&lt;span class="kwrd"&gt;&amp;gt;&amp;lt;/&lt;/span&gt;&lt;span class="html"&gt;script&lt;/span&gt;&lt;span class="kwrd"&gt;&amp;gt;&lt;/span&gt;&lt;br /&gt;      &amp;lt;script type=&lt;span class="str"&gt;"text/javascript"&lt;/span&gt;&amp;gt;&lt;br /&gt;&lt;br /&gt;      &lt;span class="kwrd"&gt;var&lt;/span&gt; map = &lt;span class="kwrd"&gt;null&lt;/span&gt;;&lt;br /&gt;      &lt;span class="kwrd"&gt;var&lt;/span&gt; findPlaceResults = &lt;span class="kwrd"&gt;null&lt;/span&gt;;&lt;br /&gt;      &lt;span class="kwrd"&gt;function&lt;/span&gt; GetMap()&lt;br /&gt;      {&lt;br /&gt;         map = &lt;span class="kwrd"&gt;new&lt;/span&gt; VEMap(&lt;span class="str"&gt;'myMap:newmap'&lt;/span&gt;);&lt;br /&gt;         map.LoadMap();&lt;br /&gt;         map.Find(&lt;span class="kwrd"&gt;null&lt;/span&gt;,&lt;span class="str"&gt;'100 Enterprise Way, Scotts Valley, CA 95066'&lt;/span&gt;, &lt;span class="kwrd"&gt;null&lt;/span&gt;, &lt;span class="kwrd"&gt;null&lt;/span&gt;, &lt;span class="kwrd"&gt;null&lt;/span&gt;, &lt;span class="kwrd"&gt;null&lt;/span&gt;, &lt;span class="kwrd"&gt;true&lt;/span&gt;, &lt;span class="kwrd"&gt;true&lt;/span&gt;, &lt;span class="kwrd"&gt;null&lt;/span&gt;, &lt;span class="kwrd"&gt;true&lt;/span&gt;, GetCoordinates);&lt;br /&gt;      }&lt;br /&gt;&lt;br /&gt;     &lt;span class="kwrd"&gt;function&lt;/span&gt; GetCoordinates(layer, resultsArray, places, hasMore, veErrorMessage)&lt;br /&gt;     {&lt;br /&gt;        findPlaceResults = places[0].LatLong;&lt;br /&gt;        &lt;span class="kwrd"&gt;var&lt;/span&gt; myShape = &lt;span class="kwrd"&gt;new&lt;/span&gt; VEShape(VEShapeType.Pushpin, findPlaceResults);&lt;br /&gt;        myShape.SetTitle(&lt;span class="str"&gt;'CodeGear'&lt;/span&gt;);&lt;br /&gt;        myShape.SetDescription(&lt;span class="str"&gt;'100 Enterprise Way&amp;lt;br&amp;gt;Scotts Valley, CA 95066&amp;lt;br&amp;gt;'&lt;/span&gt;+findPlaceResults.toString());&lt;br /&gt;        map.AddShape(myShape);&lt;br /&gt;     }&lt;br /&gt;&lt;br /&gt;     &lt;span class="kwrd"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="html"&gt;script&lt;/span&gt;&lt;span class="kwrd"&gt;&amp;gt;&lt;/span&gt;&lt;br /&gt;   &lt;span class="kwrd"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="html"&gt;head&lt;/span&gt;&lt;span class="kwrd"&gt;&amp;gt;&lt;/span&gt;&lt;br /&gt;   &lt;span class="kwrd"&gt;&amp;lt;&lt;/span&gt;&lt;span class="html"&gt;body&lt;/span&gt; &lt;span class="attr"&gt;onload&lt;/span&gt;&lt;span class="kwrd"&gt;="GetMap();"&lt;/span&gt;&lt;span class="kwrd"&gt;&amp;gt;&lt;/span&gt;&lt;br /&gt;      &lt;span class="kwrd"&gt;&amp;lt;&lt;/span&gt;&lt;span class="html"&gt;div&lt;/span&gt; &lt;span class="attr"&gt;id&lt;/span&gt;&lt;span class="kwrd"&gt;='myMap:newmap'&lt;/span&gt; &lt;span class="attr"&gt;style&lt;/span&gt;&lt;span class="kwrd"&gt;="position:relative; width:800px; height:600px;"&lt;/span&gt;&lt;span class="kwrd"&gt;&amp;gt;&amp;lt;/&lt;/span&gt;&lt;span class="html"&gt;div&lt;/span&gt;&lt;span class="kwrd"&gt;&amp;gt;&lt;/span&gt;&lt;br /&gt;   &lt;span class="kwrd"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="html"&gt;body&lt;/span&gt;&lt;span class="kwrd"&gt;&amp;gt;&lt;/span&gt;&lt;br /&gt;&lt;span class="kwrd"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="html"&gt;html&lt;/span&gt;&lt;span class="kwrd"&gt;&amp;gt;&lt;/span&gt;&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;The problem showed up when I went to add the facilities to the map. Thinking it would all work the same way, I added the same Map.Find code for each facility in the state of interest and voila. Except the voila was, "How come I only get one pushpin?" not "See how great this works!" It turns out that part of the answer is the MS VEMap object works asynchronously. I could live with that if the map moved around a little as it added pushpins... well, at the very least, I could just hide the map until it was done. &lt;br /&gt;&lt;br /&gt;Unfortunately, MS also made the calls non-reentrant. This is actually what they document the problem as. To me, the code IS non-reentrant in that it never calls itself. Apparently, our definitions of re-entrant differ significantly. To MS, non-reentrant means that you have to wait for the asynchronous call to complete before you can call it again. Of course, Javascript has little support for "waiting". I was able to create a work around using a do {} while (!completed); but it causes the browser to complain mightly, ties up a lot of CPU and is just generally ugly.&lt;br /&gt;&lt;br /&gt;Seeing that this wasn't going to work very well, I went back to the drawing board. If I actually could provide the Lat/Lng for each object, the problem would go away. It turns out that there are not very many services that want to let you do this for free using a desktop tool. If you are willing to do a web mashup you can get away with quite a bit, but the traditional languages are left out in the cold for the most part. &lt;br /&gt;&lt;br /&gt;This is where MapQuest comes in. They have a free service (you have to register, but that's it) that will let you have access to their mapping systems. Of course, they have no interface for Delphi, but they did publish their XML specifications so it's not too hard to write one. Keep in mind that you have to comply with the MapQuest TOS. The major one for me was that you can't use the Lat/Lng addresses with any other system than theirs. That means I can't use maps.live.com to produce my maps, I have to figure out how to use MapQuest. Considering my other choices was a complete web mashup rewrite or some commercial system that was going to cost a fortune, I think I'll live within those parameters.&lt;br /&gt;&lt;br /&gt;I've only implemented the single interface I needed so far (GeoCoding), but the other interfaces are equally easy. This code is virtually identical (in the HTTP POST) as my DHL code. I've reposted the whole thing here for those needing a complete unit but will likely factor it out for my personal use.&lt;br /&gt;&lt;br /&gt;Enjoy!&lt;br /&gt;&lt;br /&gt;1. This is how the classes are used. I assume you recognize that the txtXXX are just text box fields and the resolver form has a single control on it that is a list box (other than the Select / Cancel buttons).&lt;br /&gt;&lt;br /&gt;&lt;!-- code formatted by http://manoli.net/csharpformat/ --&gt;&lt;br /&gt;&lt;pre class="csharpcode"&gt;&lt;br /&gt;&lt;span class="kwrd"&gt;uses&lt;/span&gt; mapquest_api, w_AddyResolver;&lt;br /&gt;&lt;br /&gt;&lt;span class="kwrd"&gt;procedure&lt;/span&gt; TForm1.btnGeoCodeClick(S&lt;span class="kwrd"&gt;end&lt;/span&gt;er: &lt;span class="kwrd"&gt;to&lt;/span&gt;bject);&lt;br /&gt;&lt;span class="kwrd"&gt;var&lt;/span&gt; geocode:TMapQuestGeoCoder;&lt;br /&gt;    index, ix:integer;&lt;br /&gt;&lt;span class="kwrd"&gt;begin&lt;/span&gt;&lt;br /&gt;geocode:=TMapQuestGeoCoder.Create;                                               &lt;span class="rem"&gt;//create the geocoder object&lt;/span&gt;&lt;br /&gt;geocode.Password:=&lt;span class="str"&gt;'YOUR PASS'&lt;/span&gt;;                                                   &lt;span class="rem"&gt;//assign the password and client id you got from mapquest&lt;/span&gt;&lt;br /&gt;geocode.ClientID:=&lt;span class="str"&gt;'YOUR ID'&lt;/span&gt;;                                                     &lt;span class="rem"&gt;//this will NOT work &lt;span class="kwrd"&gt;with&lt;/span&gt;out it!!!&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;geocode.Address    := edtAddress.Text;                                           &lt;span class="rem"&gt;//assign the address info you want &lt;span class="kwrd"&gt;to&lt;/span&gt; code&lt;/span&gt;&lt;br /&gt;geocode.City       := edtCity.Text;&lt;br /&gt;geocode.State      := edtState.Text;&lt;br /&gt;geocode.PostalCode := edtPostalCode.Text;&lt;br /&gt;geocode.Country    := edtCountry.Text;&lt;br /&gt;&lt;br /&gt;&lt;span class="kwrd"&gt;if&lt;/span&gt; geocode.getFromMapQuest(&lt;span class="kwrd"&gt;true&lt;/span&gt;) &lt;span class="kwrd"&gt;then&lt;/span&gt;                                            &lt;span class="rem"&gt;//this will s&lt;span class="kwrd"&gt;end&lt;/span&gt; the info &lt;span class="kwrd"&gt;to&lt;/span&gt; mapquest and return the results&lt;/span&gt;&lt;br /&gt;   &lt;span class="kwrd"&gt;if&lt;/span&gt; geocode.ReturnedAddresses.Count&amp;gt;0 &lt;span class="kwrd"&gt;then&lt;/span&gt;                                     &lt;span class="rem"&gt;//if we got a response&lt;/span&gt;&lt;br /&gt;      &lt;span class="kwrd"&gt;begin&lt;/span&gt;&lt;br /&gt;      &lt;span class="kwrd"&gt;if&lt;/span&gt; geoCode.ReturnedAddresses.Count=1 &lt;span class="kwrd"&gt;then&lt;/span&gt;                                  &lt;span class="rem"&gt;//if there's only 1, no need &lt;span class="kwrd"&gt;to&lt;/span&gt; show a resolver&lt;/span&gt;&lt;br /&gt;         index:=0&lt;br /&gt;      &lt;span class="kwrd"&gt;else&lt;/span&gt;                                                                       &lt;span class="rem"&gt;//we got multiple responses, the user will have &lt;span class="kwrd"&gt;to&lt;/span&gt; resolve which addy is correct&lt;/span&gt;&lt;br /&gt;         &lt;span class="kwrd"&gt;begin&lt;/span&gt;&lt;br /&gt;         index:=-1;                                                              &lt;span class="rem"&gt;//default &lt;span class="kwrd"&gt;to&lt;/span&gt; failure&lt;/span&gt;&lt;br /&gt;         &lt;span class="kwrd"&gt;for&lt;/span&gt; ix := 0 &lt;span class="kwrd"&gt;to&lt;/span&gt; geoCode.ReturnedAddresses.Count-1 &lt;span class="kwrd"&gt;do&lt;/span&gt;                     &lt;span class="rem"&gt;//for each addy&lt;/span&gt;&lt;br /&gt;            &lt;span class="kwrd"&gt;with&lt;/span&gt; geoCode.ReturnedAddresses.Address[ix] &lt;span class="kwrd"&gt;do&lt;/span&gt;&lt;br /&gt;               addyResolver.lb.Items.Add(Address+&lt;span class="str"&gt;' '&lt;/span&gt;+City+&lt;span class="str"&gt;' '&lt;/span&gt;+State+&lt;span class="str"&gt;' '&lt;/span&gt;+Country); &lt;span class="rem"&gt;//load the listbox&lt;/span&gt;&lt;br /&gt;         &lt;span class="kwrd"&gt;if&lt;/span&gt; addyResolver.ShowModal=mrOk &lt;span class="kwrd"&gt;then&lt;/span&gt;                                     &lt;span class="rem"&gt;//prompt the user, if they select one, mrOk will be set&lt;/span&gt;&lt;br /&gt;            index:=addyResolver.lb.ItemIndex;                                    &lt;span class="rem"&gt;//get the addy&lt;/span&gt;&lt;br /&gt;         &lt;span class="kwrd"&gt;if&lt;/span&gt; index&amp;lt;0 &lt;span class="kwrd"&gt;then&lt;/span&gt; exit;                                                   &lt;span class="rem"&gt;//if the user failed &lt;span class="kwrd"&gt;to&lt;/span&gt; pick, get out&lt;/span&gt;&lt;br /&gt;         &lt;span class="kwrd"&gt;end&lt;/span&gt;;&lt;br /&gt;&lt;br /&gt;      lblLat.Caption:=geoCode.ReturnedAddresses.Address[index].Lat;              &lt;span class="rem"&gt;//display the lat and long values&lt;/span&gt;&lt;br /&gt;      lblLong.Caption:=geoCode.ReturnedAddresses.Address[index].Long;&lt;br /&gt;      &lt;span class="kwrd"&gt;end&lt;/span&gt;;&lt;br /&gt;&lt;br /&gt;&lt;span class="kwrd"&gt;end&lt;/span&gt;;&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;2. And this is the actual unit that does the work. BTW, the XML parser I'm using is OpenXML, a freely available, full source implementation that works for Delphi and Kylix. &lt;br /&gt;&lt;br /&gt;&lt;!-- code formatted by http://manoli.net/csharpformat/ --&gt;&lt;br /&gt;&lt;pre class="csharpcode"&gt;&lt;br /&gt;unit mapquest_api;&lt;br /&gt;&lt;br /&gt;&lt;span class="kwrd"&gt;interface&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span class="kwrd"&gt;uses&lt;/span&gt; classes, contnrs;&lt;br /&gt;&lt;br /&gt;&lt;span class="kwrd"&gt;type&lt;/span&gt;&lt;br /&gt;   &lt;span class="rem"&gt;//base class, you must derive desc&lt;span class="kwrd"&gt;end&lt;/span&gt;ants &lt;span class="kwrd"&gt;to&lt;/span&gt; make use of this class&lt;/span&gt;&lt;br /&gt;   &lt;span class="rem"&gt;//in order &lt;span class="kwrd"&gt;to&lt;/span&gt; successfully communicate &lt;span class="kwrd"&gt;with&lt;/span&gt; mapquest, you must attach YOUR ClientID, Password and APIKey&lt;/span&gt;&lt;br /&gt;   &lt;span class="rem"&gt;//you can register for free at mapquest.com&lt;/span&gt;&lt;br /&gt;   TMapQuestAPI = &lt;span class="kwrd"&gt;class&lt;/span&gt;&lt;br /&gt;      &lt;span class="kwrd"&gt;private&lt;/span&gt;&lt;br /&gt;         fClientID : &lt;span class="kwrd"&gt;string&lt;/span&gt;;&lt;br /&gt;         fPassword : &lt;span class="kwrd"&gt;string&lt;/span&gt;;&lt;br /&gt;         fAPIKey   : &lt;span class="kwrd"&gt;string&lt;/span&gt;;&lt;br /&gt;         fURL      : &lt;span class="kwrd"&gt;string&lt;/span&gt;;&lt;br /&gt;      &lt;span class="kwrd"&gt;protected&lt;/span&gt;&lt;br /&gt;         &lt;span class="kwrd"&gt;function&lt;/span&gt; getXML:&lt;span class="kwrd"&gt;string&lt;/span&gt;; &lt;span class="kwrd"&gt;virtual&lt;/span&gt;; &lt;span class="kwrd"&gt;abstract&lt;/span&gt;;&lt;br /&gt;         &lt;span class="kwrd"&gt;procedure&lt;/span&gt; parseResponse(response:TStringList); &lt;span class="kwrd"&gt;virtual&lt;/span&gt;; &lt;span class="kwrd"&gt;abstract&lt;/span&gt;;&lt;br /&gt;      &lt;span class="kwrd"&gt;public&lt;/span&gt;&lt;br /&gt;         &lt;span class="kwrd"&gt;constructor&lt;/span&gt; Create;&lt;br /&gt;         &lt;span class="kwrd"&gt;function&lt;/span&gt; getFromMapQuest(enableLogging:boolean):boolean;&lt;br /&gt;&lt;br /&gt;         property ClientID : &lt;span class="kwrd"&gt;string&lt;/span&gt; &lt;span class="kwrd"&gt;read&lt;/span&gt; fClientID &lt;span class="kwrd"&gt;write&lt;/span&gt; fClientID;&lt;br /&gt;         property Password : &lt;span class="kwrd"&gt;string&lt;/span&gt; &lt;span class="kwrd"&gt;read&lt;/span&gt; fPassword &lt;span class="kwrd"&gt;write&lt;/span&gt; fPassword;&lt;br /&gt;         property APIKey   : &lt;span class="kwrd"&gt;string&lt;/span&gt; &lt;span class="kwrd"&gt;read&lt;/span&gt; fAPIKey   &lt;span class="kwrd"&gt;write&lt;/span&gt; fAPIKey;&lt;br /&gt;         property URL      : &lt;span class="kwrd"&gt;string&lt;/span&gt; &lt;span class="kwrd"&gt;read&lt;/span&gt; fURL;&lt;br /&gt;      &lt;span class="kwrd"&gt;end&lt;/span&gt;;&lt;br /&gt;&lt;br /&gt;   TReturnedAddyList=&lt;span class="kwrd"&gt;class&lt;/span&gt;;&lt;br /&gt;&lt;br /&gt;   &lt;span class="rem"&gt;//this desc&lt;span class="kwrd"&gt;end&lt;/span&gt;ant will implement the GeoCoder &lt;span class="kwrd"&gt;function&lt;/span&gt;ality from mapquest&lt;/span&gt;&lt;br /&gt;   &lt;span class="rem"&gt;//you must comply &lt;span class="kwrd"&gt;with&lt;/span&gt; mapquests terms of service, check mapquest.com &lt;span class="kwrd"&gt;to&lt;/span&gt; make sure&lt;/span&gt;&lt;br /&gt;   &lt;span class="rem"&gt;//that works for you&lt;/span&gt;&lt;br /&gt;   TMapQuestGeoCoder = &lt;span class="kwrd"&gt;class&lt;/span&gt;(TMapQuestAPI)&lt;br /&gt;      &lt;span class="kwrd"&gt;private&lt;/span&gt;&lt;br /&gt;         fAddress   : &lt;span class="kwrd"&gt;string&lt;/span&gt;;&lt;br /&gt;         fState     : &lt;span class="kwrd"&gt;string&lt;/span&gt;;&lt;br /&gt;         fCity      : &lt;span class="kwrd"&gt;string&lt;/span&gt;;&lt;br /&gt;         fCountry   : &lt;span class="kwrd"&gt;string&lt;/span&gt;;&lt;br /&gt;         fPostalCode: &lt;span class="kwrd"&gt;string&lt;/span&gt;;&lt;br /&gt;         fCounty    : &lt;span class="kwrd"&gt;string&lt;/span&gt;;&lt;br /&gt;         fReturnedAddresses : TReturnedAddyList;&lt;br /&gt;      &lt;span class="kwrd"&gt;protected&lt;/span&gt;&lt;br /&gt;         &lt;span class="kwrd"&gt;function&lt;/span&gt; getXML:&lt;span class="kwrd"&gt;string&lt;/span&gt;; &lt;span class="kwrd"&gt;override&lt;/span&gt;;&lt;br /&gt;         &lt;span class="kwrd"&gt;procedure&lt;/span&gt; parseResponse(response:TStringList); &lt;span class="kwrd"&gt;override&lt;/span&gt;;&lt;br /&gt;         &lt;span class="kwrd"&gt;procedure&lt;/span&gt; ClearReturnedAddys;&lt;br /&gt;      &lt;span class="kwrd"&gt;public&lt;/span&gt;&lt;br /&gt;         &lt;span class="kwrd"&gt;constructor&lt;/span&gt; Create;&lt;br /&gt;         destruc&lt;span class="kwrd"&gt;to&lt;/span&gt;r Done;&lt;br /&gt;&lt;br /&gt;         property Address:&lt;span class="kwrd"&gt;string&lt;/span&gt;    &lt;span class="kwrd"&gt;read&lt;/span&gt; fAddress    &lt;span class="kwrd"&gt;write&lt;/span&gt; fAddress;&lt;br /&gt;         property City:&lt;span class="kwrd"&gt;string&lt;/span&gt;       &lt;span class="kwrd"&gt;read&lt;/span&gt; fCity       &lt;span class="kwrd"&gt;write&lt;/span&gt; fCity;&lt;br /&gt;         property State:&lt;span class="kwrd"&gt;string&lt;/span&gt;      &lt;span class="kwrd"&gt;read&lt;/span&gt; fState      &lt;span class="kwrd"&gt;write&lt;/span&gt; fState;&lt;br /&gt;         property Country:&lt;span class="kwrd"&gt;string&lt;/span&gt;    &lt;span class="kwrd"&gt;read&lt;/span&gt; fCountry    &lt;span class="kwrd"&gt;write&lt;/span&gt; fCountry;&lt;br /&gt;         property PostalCode:&lt;span class="kwrd"&gt;string&lt;/span&gt; &lt;span class="kwrd"&gt;read&lt;/span&gt; fPostalCode &lt;span class="kwrd"&gt;write&lt;/span&gt; fPostalCode;&lt;br /&gt;         property County:&lt;span class="kwrd"&gt;string&lt;/span&gt;     &lt;span class="kwrd"&gt;read&lt;/span&gt; fCounty     &lt;span class="kwrd"&gt;write&lt;/span&gt; fCounty;&lt;br /&gt;         property ReturnedAddresses:TReturnedAddyList &lt;span class="kwrd"&gt;read&lt;/span&gt; fReturnedAddresses;&lt;br /&gt;      &lt;span class="kwrd"&gt;end&lt;/span&gt;;&lt;br /&gt;&lt;br /&gt;   &lt;span class="rem"&gt;//container class for a returned address&lt;/span&gt;&lt;br /&gt;   TReturnedAddy = &lt;span class="kwrd"&gt;class&lt;/span&gt;&lt;br /&gt;      &lt;span class="kwrd"&gt;public&lt;/span&gt;&lt;br /&gt;         Address,&lt;br /&gt;         City,&lt;br /&gt;         State,&lt;br /&gt;         PostalCode,&lt;br /&gt;         Country,&lt;br /&gt;         County,&lt;br /&gt;         Lat,&lt;br /&gt;         Long      : &lt;span class="kwrd"&gt;string&lt;/span&gt;;&lt;br /&gt;&lt;br /&gt;         &lt;span class="kwrd"&gt;constructor&lt;/span&gt; Create(aAddress, aCity, aState, aPostalCode, aCountry, aCounty, aLat, aLong:&lt;span class="kwrd"&gt;string&lt;/span&gt;);&lt;br /&gt;      &lt;span class="kwrd"&gt;end&lt;/span&gt;;&lt;br /&gt;&lt;br /&gt;   &lt;span class="rem"&gt;//you can get back MULTIPLE addresses if you s&lt;span class="kwrd"&gt;end&lt;/span&gt; in something that is generic enough&lt;/span&gt;&lt;br /&gt;   &lt;span class="rem"&gt;//in that case, the COUNT will be &amp;gt; 1. Make sure you implement a resolver screen &lt;span class="kwrd"&gt;to&lt;/span&gt; handle this&lt;/span&gt;&lt;br /&gt;   TReturnedAddyList = &lt;span class="kwrd"&gt;class&lt;/span&gt;(TList)&lt;br /&gt;      &lt;span class="kwrd"&gt;protected&lt;/span&gt;&lt;br /&gt;         property Items;&lt;br /&gt;         property List;&lt;br /&gt;      &lt;span class="kwrd"&gt;public&lt;/span&gt;&lt;br /&gt;         &lt;span class="kwrd"&gt;function&lt;/span&gt; getAddy(index:integer):TReturnedAddy;&lt;br /&gt;         property Address[Index:Integer]:TReturnedAddy &lt;span class="kwrd"&gt;read&lt;/span&gt; getAddy;&lt;br /&gt;      &lt;span class="kwrd"&gt;end&lt;/span&gt;;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;span class="kwrd"&gt;implementation&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span class="kwrd"&gt;uses&lt;/span&gt; sysutils, dialogs, IdHttp, IdSSLOpenSSL, IdResourceStringsCore, IdLogFile, xdom_3_2;&lt;br /&gt;&lt;br /&gt;&lt;span class="kwrd"&gt;const&lt;/span&gt;&lt;br /&gt;   CR = #13;&lt;br /&gt;   LF = #10;&lt;br /&gt;   EOL = CR+LF;&lt;br /&gt;   xmlEOL = EOL;&lt;br /&gt;&lt;br /&gt;&lt;span class="kwrd"&gt;type&lt;/span&gt;&lt;br /&gt;  &lt;span class="rem"&gt;// this is a desc&lt;span class="kwrd"&gt;end&lt;/span&gt;ant of TidLogFile, it will create a plain text file &lt;span class="kwrd"&gt;with&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;  &lt;span class="rem"&gt;// information about the transfer session&lt;/span&gt;&lt;br /&gt;  TlogFile = &lt;span class="kwrd"&gt;class&lt;/span&gt;(TidLogFile)&lt;br /&gt;  &lt;span class="kwrd"&gt;protected&lt;/span&gt;&lt;br /&gt;    &lt;span class="kwrd"&gt;procedure&lt;/span&gt; LogReceivedData(&lt;span class="kwrd"&gt;const&lt;/span&gt; AText, AData: &lt;span class="kwrd"&gt;string&lt;/span&gt;); &lt;span class="kwrd"&gt;override&lt;/span&gt;;&lt;br /&gt;    &lt;span class="kwrd"&gt;procedure&lt;/span&gt; LogSentData(&lt;span class="kwrd"&gt;const&lt;/span&gt; AText, AData: &lt;span class="kwrd"&gt;string&lt;/span&gt;); &lt;span class="kwrd"&gt;override&lt;/span&gt;;&lt;br /&gt;    &lt;span class="kwrd"&gt;procedure&lt;/span&gt; LogStatus(&lt;span class="kwrd"&gt;const&lt;/span&gt; AText: &lt;span class="kwrd"&gt;string&lt;/span&gt;); &lt;span class="kwrd"&gt;override&lt;/span&gt;;&lt;br /&gt;  &lt;span class="kwrd"&gt;public&lt;/span&gt;&lt;br /&gt;    &lt;span class="kwrd"&gt;procedure&lt;/span&gt; Log&lt;span class="kwrd"&gt;write&lt;/span&gt;String(&lt;span class="kwrd"&gt;const&lt;/span&gt; AText: &lt;span class="kwrd"&gt;string&lt;/span&gt;); &lt;span class="kwrd"&gt;override&lt;/span&gt;;&lt;br /&gt;    &lt;span class="kwrd"&gt;class&lt;/span&gt; &lt;span class="kwrd"&gt;function&lt;/span&gt; buildLogLine(data, prefix: &lt;span class="kwrd"&gt;string&lt;/span&gt;) : &lt;span class="kwrd"&gt;string&lt;/span&gt;;&lt;br /&gt;  &lt;span class="kwrd"&gt;end&lt;/span&gt;;&lt;br /&gt;&lt;br /&gt;&lt;span class="rem"&gt;// this ensures the output of error and debug logs are in the same format, regardless of source&lt;/span&gt;&lt;br /&gt;&lt;span class="kwrd"&gt;class&lt;/span&gt; &lt;span class="kwrd"&gt;function&lt;/span&gt; TlogFile.buildLogLine(data, prefix: &lt;span class="kwrd"&gt;string&lt;/span&gt;) : &lt;span class="kwrd"&gt;string&lt;/span&gt;;&lt;br /&gt;&lt;span class="kwrd"&gt;begin&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;  data := StringReplace(data, EOL, RSLogEOL, [rfReplaceAll]);&lt;br /&gt;  data := StringReplace(data, CR,  RSLogCR,  [rfReplaceAll]);&lt;br /&gt;  data := StringReplace(data, LF,  RSLogLF,  [rfReplaceAll]);&lt;br /&gt;&lt;br /&gt;  result := FormatDateTime(&lt;span class="str"&gt;'yy/mm/dd hh:nn:ss'&lt;/span&gt;, now) + &lt;span class="str"&gt;' '&lt;/span&gt;;&lt;br /&gt;  &lt;span class="kwrd"&gt;if&lt;/span&gt; (prefix &amp;lt;&amp;gt; &lt;span class="str"&gt;''&lt;/span&gt;) &lt;span class="kwrd"&gt;then&lt;/span&gt;&lt;br /&gt;    result := result + prefix + &lt;span class="str"&gt;' '&lt;/span&gt;;&lt;br /&gt;  result := result + data + EOL;&lt;br /&gt;&lt;span class="kwrd"&gt;end&lt;/span&gt;;&lt;br /&gt;&lt;br /&gt;&lt;span class="rem"&gt;// ---------------------------------------------------------------------------&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span class="kwrd"&gt;procedure&lt;/span&gt; TlogFile.LogReceivedData(&lt;span class="kwrd"&gt;const&lt;/span&gt; AText, AData: &lt;span class="kwrd"&gt;string&lt;/span&gt;);&lt;br /&gt;&lt;span class="kwrd"&gt;begin&lt;/span&gt;&lt;br /&gt;  &lt;span class="rem"&gt;// ignore AText as it contains the date/time&lt;/span&gt;&lt;br /&gt;  Log&lt;span class="kwrd"&gt;write&lt;/span&gt;String(buildLogLine(Adata, &lt;span class="str"&gt;'&amp;lt;&amp;lt;'&lt;/span&gt;));&lt;br /&gt;&lt;span class="kwrd"&gt;end&lt;/span&gt;;&lt;br /&gt;&lt;br /&gt;&lt;span class="rem"&gt;// ---------------------------------------------------------------------------&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span class="kwrd"&gt;procedure&lt;/span&gt; TlogFile.LogSentData(&lt;span class="kwrd"&gt;const&lt;/span&gt; AText, AData: &lt;span class="kwrd"&gt;string&lt;/span&gt;);&lt;br /&gt;&lt;span class="kwrd"&gt;begin&lt;/span&gt;&lt;br /&gt;  &lt;span class="rem"&gt;// ignore AText as it contains the date/time&lt;/span&gt;&lt;br /&gt;  Log&lt;span class="kwrd"&gt;write&lt;/span&gt;String(buildLogLine(Adata, &lt;span class="str"&gt;'&amp;gt;&amp;gt;'&lt;/span&gt;));&lt;br /&gt;&lt;span class="kwrd"&gt;end&lt;/span&gt;;&lt;br /&gt;&lt;br /&gt;&lt;span class="rem"&gt;// ---------------------------------------------------------------------------&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span class="kwrd"&gt;procedure&lt;/span&gt; TlogFile.LogStatus(&lt;span class="kwrd"&gt;const&lt;/span&gt; AText: &lt;span class="kwrd"&gt;string&lt;/span&gt;);&lt;br /&gt;&lt;span class="kwrd"&gt;begin&lt;/span&gt;&lt;br /&gt;  Log&lt;span class="kwrd"&gt;write&lt;/span&gt;String(buildLogLine(AText, &lt;span class="str"&gt;'**'&lt;/span&gt;));&lt;br /&gt;&lt;span class="kwrd"&gt;end&lt;/span&gt;;&lt;br /&gt;&lt;br /&gt;&lt;span class="rem"&gt;// ---------------------------------------------------------------------------&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span class="kwrd"&gt;procedure&lt;/span&gt; TlogFile.Log&lt;span class="kwrd"&gt;write&lt;/span&gt;String(&lt;span class="kwrd"&gt;const&lt;/span&gt; AText: &lt;span class="kwrd"&gt;string&lt;/span&gt;);&lt;br /&gt;&lt;span class="kwrd"&gt;begin&lt;/span&gt;&lt;br /&gt;  &lt;span class="rem"&gt;// protected --&amp;gt; public&lt;/span&gt;&lt;br /&gt;  inherited;&lt;br /&gt;&lt;span class="kwrd"&gt;end&lt;/span&gt;;&lt;br /&gt;&lt;br /&gt;&lt;span class="rem"&gt;// ---------------------------------------------------------------------------&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;{ TMapQuestAPI }&lt;br /&gt;&lt;br /&gt;&lt;span class="rem"&gt;//create the class, default everything &lt;span class="kwrd"&gt;to&lt;/span&gt; blank&lt;/span&gt;&lt;br /&gt;&lt;span class="kwrd"&gt;constructor&lt;/span&gt; TMapQuestAPI.Create;&lt;br /&gt;&lt;span class="kwrd"&gt;begin&lt;/span&gt;&lt;br /&gt;fURL:=&lt;span class="str"&gt;''&lt;/span&gt;;&lt;br /&gt;fClientID:=&lt;span class="str"&gt;''&lt;/span&gt;;&lt;br /&gt;fPassword:=&lt;span class="str"&gt;''&lt;/span&gt;;&lt;br /&gt;fAPIKey:=&lt;span class="str"&gt;''&lt;/span&gt;;&lt;br /&gt;&lt;span class="kwrd"&gt;end&lt;/span&gt;;&lt;br /&gt;&lt;br /&gt;&lt;span class="rem"&gt;// ---------------------------------------------------------------------------&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span class="rem"&gt;//s&lt;span class="kwrd"&gt;end&lt;/span&gt; the http post &lt;span class="kwrd"&gt;to&lt;/span&gt; mapquest and return a stringlist &lt;span class="kwrd"&gt;with&lt;/span&gt; the results (or nil if error)&lt;/span&gt;&lt;br /&gt;&lt;span class="kwrd"&gt;function&lt;/span&gt; TMapQuestAPI.getFromMapQuest(enableLogging:boolean): boolean;&lt;br /&gt;&lt;span class="kwrd"&gt;const&lt;/span&gt; logFileName = &lt;span class="str"&gt;'http.log'&lt;/span&gt;;&lt;br /&gt;&lt;span class="kwrd"&gt;var&lt;/span&gt;&lt;br /&gt;  plainData : TStringList;&lt;br /&gt;  HTTP     : TidHTTP;&lt;br /&gt;  response : TStringList;&lt;br /&gt;  logFile  : TLogFile;&lt;br /&gt;&lt;br /&gt;  &lt;span class="rem"&gt;//as mentioned in my article on http post for DHL, indy converts CR/LF pairs &lt;span class="kwrd"&gt;to&lt;/span&gt; &amp;amp;.&lt;/span&gt;&lt;br /&gt;  &lt;span class="rem"&gt;//This ca&lt;span class="kwrd"&gt;uses&lt;/span&gt; a problem when s&lt;span class="kwrd"&gt;end&lt;/span&gt;ing xml data.&lt;/span&gt;&lt;br /&gt;  &lt;span class="rem"&gt;//This routine will remove CR/LF pairs and replace them &lt;span class="kwrd"&gt;with&lt;/span&gt; a space&lt;/span&gt;&lt;br /&gt;  &lt;span class="kwrd"&gt;procedure&lt;/span&gt; ConvertCRLF&lt;span class="kwrd"&gt;to&lt;/span&gt;Space;&lt;br /&gt;  &lt;span class="kwrd"&gt;begin&lt;/span&gt;&lt;br /&gt;    &lt;span class="kwrd"&gt;if&lt;/span&gt; plainData.Count &amp;gt; 1 &lt;span class="kwrd"&gt;then&lt;/span&gt; &lt;span class="kwrd"&gt;begin&lt;/span&gt;&lt;br /&gt;      &lt;span class="rem"&gt;// break trailing CR&amp;amp;LF&lt;/span&gt;&lt;br /&gt;      plainData.Text := StringReplace(Trim(plainData.Text), sLineBreak, &lt;span class="str"&gt;' '&lt;/span&gt;,[rfReplaceAll]);&lt;br /&gt;    &lt;span class="kwrd"&gt;end&lt;/span&gt; &lt;span class="kwrd"&gt;else&lt;/span&gt; &lt;span class="kwrd"&gt;begin&lt;/span&gt;&lt;br /&gt;      plainData.Text := Trim(plainData.Text);&lt;br /&gt;    &lt;span class="kwrd"&gt;end&lt;/span&gt;;&lt;br /&gt;  &lt;span class="kwrd"&gt;end&lt;/span&gt;;&lt;br /&gt;&lt;br /&gt;&lt;span class="kwrd"&gt;begin&lt;/span&gt;&lt;br /&gt;  result:=&lt;span class="kwrd"&gt;false&lt;/span&gt;;                                                           &lt;span class="rem"&gt;//by default, we get failure response in error&lt;/span&gt;&lt;br /&gt;  plainData := TStringList.Create;                                         &lt;span class="rem"&gt;//init the container for xmiting the xml&lt;/span&gt;&lt;br /&gt;  &lt;span class="kwrd"&gt;try&lt;/span&gt;&lt;br /&gt;     plainData.Text:=getXML;                                               &lt;span class="rem"&gt;//get the xml from the class and put it in the container&lt;/span&gt;&lt;br /&gt;     Http:=TidHTTP.Create(nil);                                            &lt;span class="rem"&gt;//create the http class&lt;/span&gt;&lt;br /&gt;     &lt;span class="kwrd"&gt;try&lt;/span&gt;&lt;br /&gt;        HTTP.&lt;span class="kwrd"&gt;read&lt;/span&gt;Timeout := 10000;                                         &lt;span class="rem"&gt;//setup the http timeouts and xmit &lt;span class="kwrd"&gt;type&lt;/span&gt;s&lt;/span&gt;&lt;br /&gt;        HTTP.ConnectTimeout := 10000;&lt;br /&gt;        HTTP.Request.Content&lt;span class="kwrd"&gt;type&lt;/span&gt; := &lt;span class="str"&gt;'text/xml'&lt;/span&gt;;&lt;br /&gt;        HTTP.HTTPOptions := [];&lt;br /&gt;        &lt;span class="kwrd"&gt;if&lt;/span&gt; enableLogging &lt;span class="kwrd"&gt;then&lt;/span&gt;                                              &lt;span class="rem"&gt;//if we are going &lt;span class="kwrd"&gt;to&lt;/span&gt; log the events (useful if there's a problem)&lt;/span&gt;&lt;br /&gt;           &lt;span class="kwrd"&gt;begin&lt;/span&gt;&lt;br /&gt;           logFile := TLogFile.Create(nil);                                &lt;span class="rem"&gt;//create the log file&lt;/span&gt;&lt;br /&gt;           logFile.FileName:=logFileName;                                  &lt;span class="rem"&gt;//set the default log file name - NOTE: you could get fancy &lt;span class="kwrd"&gt;with&lt;/span&gt; this, but I normally don't use it&lt;/span&gt;&lt;br /&gt;           logFile.Active:=&lt;span class="kwrd"&gt;true&lt;/span&gt;;                                           &lt;span class="rem"&gt;//activate the log file (creates the file and intializes everything)&lt;/span&gt;&lt;br /&gt;           HTTP.Intercept := logFile;                                      &lt;span class="rem"&gt;//set the logFile &lt;span class="kwrd"&gt;to&lt;/span&gt; the intercept of the HTTP &lt;span class="kwrd"&gt;to&lt;/span&gt; capture the events&lt;/span&gt;&lt;br /&gt;           &lt;span class="kwrd"&gt;end&lt;/span&gt;;&lt;br /&gt;        response:=TStringList.Create;                                      &lt;span class="rem"&gt;//create the response container&lt;/span&gt;&lt;br /&gt;        &lt;span class="kwrd"&gt;try&lt;/span&gt;&lt;br /&gt;           ConvertCRLF&lt;span class="kwrd"&gt;to&lt;/span&gt;Space;                                             &lt;span class="rem"&gt;//make sure you strip cr/lf pairs out or the xml will be malformed&lt;/span&gt;&lt;br /&gt;           response.Text := HTTP.Post(URL, plainData);                     &lt;span class="rem"&gt;//post the xml and receive the response xml&lt;/span&gt;&lt;br /&gt;           result:=&lt;span class="kwrd"&gt;true&lt;/span&gt;;&lt;br /&gt;           parseResponse(response);&lt;br /&gt;        &lt;span class="kwrd"&gt;finally&lt;/span&gt;&lt;br /&gt;           response.Free;&lt;br /&gt;        &lt;span class="kwrd"&gt;end&lt;/span&gt;;&lt;br /&gt;     &lt;span class="kwrd"&gt;finally&lt;/span&gt;&lt;br /&gt;        Http.free;                                                         &lt;span class="rem"&gt;//free the http class&lt;/span&gt;&lt;br /&gt;     &lt;span class="kwrd"&gt;end&lt;/span&gt;;&lt;br /&gt;  &lt;span class="kwrd"&gt;finally&lt;/span&gt;&lt;br /&gt;     plainData.Free;                                                       &lt;span class="rem"&gt;//free the container class&lt;/span&gt;&lt;br /&gt;  &lt;span class="kwrd"&gt;end&lt;/span&gt;;&lt;br /&gt;&lt;br /&gt;&lt;span class="kwrd"&gt;end&lt;/span&gt;;&lt;br /&gt;&lt;br /&gt;{ TMapQuestGeoCoder }&lt;br /&gt;&lt;br /&gt;&lt;span class="kwrd"&gt;procedure&lt;/span&gt; TMapQuestGeoCoder.ClearReturnedAddys;&lt;br /&gt;&lt;span class="kwrd"&gt;var&lt;/span&gt; ix:integer;&lt;br /&gt;&lt;span class="kwrd"&gt;begin&lt;/span&gt;&lt;br /&gt;&lt;span class="kwrd"&gt;for&lt;/span&gt; ix := 0 &lt;span class="kwrd"&gt;to&lt;/span&gt; fReturnedAddresses.Count-1 &lt;span class="kwrd"&gt;do&lt;/span&gt;&lt;br /&gt;   fReturnedAddresses.Address[ix].Free;&lt;br /&gt;fReturnedAddresses.Clear;&lt;br /&gt;&lt;span class="kwrd"&gt;end&lt;/span&gt;;&lt;br /&gt;&lt;br /&gt;&lt;span class="kwrd"&gt;constructor&lt;/span&gt; TMapQuestGeoCoder.Create;&lt;br /&gt;&lt;span class="kwrd"&gt;begin&lt;/span&gt;&lt;br /&gt;fURL:=&lt;span class="str"&gt;'http://geocode.free.mapquest.com/mq/mqserver.dll?e=5&amp;amp;'&lt;/span&gt;;            &lt;span class="rem"&gt;//this is the free server address. if you sign up for a different &lt;span class="kwrd"&gt;type&lt;/span&gt; of account, you'll want &lt;span class="kwrd"&gt;to&lt;/span&gt; set this &lt;span class="kwrd"&gt;to&lt;/span&gt; your account &lt;span class="kwrd"&gt;type&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;fReturnedAddresses:=TReturnedAddyList.Create;&lt;br /&gt;&lt;span class="kwrd"&gt;end&lt;/span&gt;;&lt;br /&gt;&lt;br /&gt;destruc&lt;span class="kwrd"&gt;to&lt;/span&gt;r TMapQuestGeoCoder.Done;&lt;br /&gt;&lt;span class="kwrd"&gt;begin&lt;/span&gt;&lt;br /&gt;ClearReturnedAddys;&lt;br /&gt;fReturnedAddresses.Free;&lt;br /&gt;&lt;span class="kwrd"&gt;end&lt;/span&gt;;&lt;br /&gt;&lt;br /&gt;&lt;span class="kwrd"&gt;function&lt;/span&gt; TMapQuestGeoCoder.getXML: &lt;span class="kwrd"&gt;string&lt;/span&gt;;                                &lt;span class="rem"&gt;//returns the xml formated per the MapQuest API&lt;/span&gt;&lt;br /&gt;&lt;span class="kwrd"&gt;const&lt;/span&gt; geocodeXML =&lt;br /&gt;   &lt;span class="str"&gt;'&amp;lt;?xml version="1.0" encoding="ISO-8859-1"?&amp;gt;'&lt;/span&gt;+&lt;br /&gt;   &lt;span class="str"&gt;'&amp;lt;Geocode version="1"&amp;gt;'&lt;/span&gt;+&lt;br /&gt;&lt;br /&gt;      &lt;span class="str"&gt;'&amp;lt;Address&amp;gt;'&lt;/span&gt;+&lt;br /&gt;        &lt;span class="str"&gt;'&amp;lt;AdminArea1&amp;gt;%s&amp;lt;/AdminArea1&amp;gt;'&lt;/span&gt;+&lt;br /&gt;        &lt;span class="str"&gt;'&amp;lt;AdminArea3&amp;gt;%s&amp;lt;/AdminArea3&amp;gt;'&lt;/span&gt;+&lt;br /&gt;        &lt;span class="str"&gt;'&amp;lt;AdminArea5&amp;gt;%s&amp;lt;/AdminArea5&amp;gt;'&lt;/span&gt;+&lt;br /&gt;        &lt;span class="str"&gt;'&amp;lt;PostalCode&amp;gt;%s&amp;lt;/PostalCode&amp;gt;'&lt;/span&gt;+&lt;br /&gt;        &lt;span class="str"&gt;'&amp;lt;Street&amp;gt;%s&amp;lt;/Street&amp;gt;'&lt;/span&gt;+&lt;br /&gt;      &lt;span class="str"&gt;'&amp;lt;/Address&amp;gt;'&lt;/span&gt;+&lt;br /&gt;&lt;br /&gt;      &lt;span class="str"&gt;'&amp;lt;GeocodeOptionsCollection Count="0"/&amp;gt;'&lt;/span&gt;+&lt;br /&gt;&lt;br /&gt;      &lt;span class="str"&gt;'&amp;lt;Au&lt;span class="kwrd"&gt;then&lt;/span&gt;tication Version="2"&amp;gt;'&lt;/span&gt;+&lt;br /&gt;        &lt;span class="str"&gt;'&amp;lt;Password&amp;gt;%s&amp;lt;/Password&amp;gt;'&lt;/span&gt;+&lt;br /&gt;        &lt;span class="str"&gt;'&amp;lt;ClientId&amp;gt;%s&amp;lt;/ClientId&amp;gt;'&lt;/span&gt;+&lt;br /&gt;      &lt;span class="str"&gt;'&amp;lt;/Au&lt;span class="kwrd"&gt;then&lt;/span&gt;tication&amp;gt;'&lt;/span&gt;+&lt;br /&gt;   &lt;span class="str"&gt;'&amp;lt;/Geocode&amp;gt;'&lt;/span&gt;;&lt;br /&gt;&lt;br /&gt;&lt;span class="kwrd"&gt;begin&lt;/span&gt;&lt;br /&gt;result := Format(geocodeXML, [Country,State,City,PostalCode,Address,Password,ClientID]);  &lt;span class="rem"&gt;//make the request xml for geocding an address&lt;/span&gt;&lt;br /&gt;&lt;span class="kwrd"&gt;end&lt;/span&gt;;&lt;br /&gt;&lt;br /&gt;&lt;span class="kwrd"&gt;procedure&lt;/span&gt; TMapQuestGeoCoder.parseResponse(response: TStringList);&lt;br /&gt;&lt;span class="kwrd"&gt;var&lt;/span&gt;&lt;br /&gt;    DOC:TXML&lt;span class="kwrd"&gt;to&lt;/span&gt;DomParser;&lt;br /&gt;    DOM:TDOMImplementation;&lt;br /&gt;    XML:TDOMDocument;&lt;br /&gt;    LocCollection:TDomNodeList;&lt;br /&gt;    Geo,&lt;br /&gt;    Node:TDomNode;&lt;br /&gt;&lt;br /&gt;    &lt;span class="rem"&gt;//you can't trust that the xml contains ALL element names so this wraps the testing conditions up&lt;/span&gt;&lt;br /&gt;    &lt;span class="rem"&gt;//&lt;span class="kwrd"&gt;to&lt;/span&gt; safely get the node values or a blank when not in the xml&lt;/span&gt;&lt;br /&gt;    &lt;span class="kwrd"&gt;function&lt;/span&gt; SafeGetNodeValue(node:TDomNode; name:&lt;span class="kwrd"&gt;string&lt;/span&gt;):&lt;span class="kwrd"&gt;string&lt;/span&gt;;&lt;br /&gt;    &lt;span class="kwrd"&gt;var&lt;/span&gt; DomElement:TDomElement;&lt;br /&gt;    &lt;span class="kwrd"&gt;begin&lt;/span&gt;&lt;br /&gt;       result:=&lt;span class="str"&gt;''&lt;/span&gt;;&lt;br /&gt;       DomElement:=Node.GetFirstChildElement(name);&lt;br /&gt;       &lt;span class="kwrd"&gt;if&lt;/span&gt; DomElement=nil &lt;span class="kwrd"&gt;then&lt;/span&gt; exit;&lt;br /&gt;       &lt;span class="kwrd"&gt;if&lt;/span&gt; DomElement.ChildNodes=nil &lt;span class="kwrd"&gt;then&lt;/span&gt; exit;&lt;br /&gt;       &lt;span class="kwrd"&gt;if&lt;/span&gt; DomElement.ChildNodes.Length=0 &lt;span class="kwrd"&gt;then&lt;/span&gt; exit;&lt;br /&gt;       result:=DomElement.ChildNodes.Item(0).NodeValue;&lt;br /&gt;    &lt;span class="kwrd"&gt;end&lt;/span&gt;;&lt;br /&gt;&lt;br /&gt;    &lt;span class="rem"&gt;//same as the previous but designed &lt;span class="kwrd"&gt;to&lt;/span&gt; get a subelement (LatLng/Lat or LatLng/Lng)&lt;/span&gt;&lt;br /&gt;    &lt;span class="kwrd"&gt;function&lt;/span&gt; SafeGetSubNodeValue(node:TDomNode; rootName, subName:&lt;span class="kwrd"&gt;string&lt;/span&gt;):&lt;span class="kwrd"&gt;string&lt;/span&gt;;&lt;br /&gt;    &lt;span class="kwrd"&gt;var&lt;/span&gt; RootElement,&lt;br /&gt;        SubElement:TDomElement;&lt;br /&gt;    &lt;span class="kwrd"&gt;begin&lt;/span&gt;&lt;br /&gt;       result:=&lt;span class="str"&gt;''&lt;/span&gt;;&lt;br /&gt;       RootElement:=Node.GetFirstChildElement(rootName);&lt;br /&gt;       &lt;span class="kwrd"&gt;if&lt;/span&gt; RootElement=nil &lt;span class="kwrd"&gt;then&lt;/span&gt; exit;&lt;br /&gt;       SubElement:=RootElement.GetFirstChildElement(subName);&lt;br /&gt;       &lt;span class="kwrd"&gt;if&lt;/span&gt; subElement=nil &lt;span class="kwrd"&gt;then&lt;/span&gt; exit;&lt;br /&gt;       &lt;span class="kwrd"&gt;if&lt;/span&gt; subElement.ChildNodes=nil &lt;span class="kwrd"&gt;then&lt;/span&gt; exit;&lt;br /&gt;       &lt;span class="kwrd"&gt;if&lt;/span&gt; subElement.ChildNodes.Length=0 &lt;span class="kwrd"&gt;then&lt;/span&gt; exit;&lt;br /&gt;       result:=subElement.ChildNodes.Item(0).NodeValue;&lt;br /&gt;    &lt;span class="kwrd"&gt;end&lt;/span&gt;;&lt;br /&gt;&lt;br /&gt;&lt;span class="kwrd"&gt;begin&lt;/span&gt;&lt;br /&gt;   ClearReturnedAddys;                                                                             &lt;span class="rem"&gt;//make sure there are no saved addys&lt;/span&gt;&lt;br /&gt;   DOC:=TXML&lt;span class="kwrd"&gt;to&lt;/span&gt;DomParser.Create(nil);                                                               &lt;span class="rem"&gt;//create the xml parser&lt;/span&gt;&lt;br /&gt;   DOM:=TDOMImplementation.Create(nil);                                                            &lt;span class="rem"&gt;//create the dom&lt;/span&gt;&lt;br /&gt;   &lt;span class="kwrd"&gt;try&lt;/span&gt;&lt;br /&gt;     DOC.DOMImpl:=DOM;                                                                             &lt;span class="rem"&gt;//assign the dom &lt;span class="kwrd"&gt;to&lt;/span&gt; the xml parser&lt;/span&gt;&lt;br /&gt;     XML := DOC.String&lt;span class="kwrd"&gt;to&lt;/span&gt;Dom(response.Text,&lt;span class="str"&gt;'mapquest.xml'&lt;/span&gt;,nil,&lt;span class="kwrd"&gt;true&lt;/span&gt;);                                &lt;span class="rem"&gt;//convert the response text &lt;span class="kwrd"&gt;to&lt;/span&gt; and xml document. NOTE: 'mapquest.xml' forces the correct creation of the node structures. If you pass blank, you get NO NODES&lt;/span&gt;&lt;br /&gt;     &lt;span class="kwrd"&gt;try&lt;/span&gt;&lt;br /&gt;        LocCollection := XML.GetElementsByTagName(&lt;span class="str"&gt;'LocationCollection'&lt;/span&gt;);                           &lt;span class="rem"&gt;//get the location collection (group of geoaddresses 1..n)&lt;/span&gt;&lt;br /&gt;        &lt;span class="kwrd"&gt;if&lt;/span&gt; LocCollection=nil &lt;span class="kwrd"&gt;then&lt;/span&gt; exit;&lt;br /&gt;&lt;br /&gt;        Node:=LocCollection.Item(0);                                                               &lt;span class="rem"&gt;//get the &lt;span class="kwrd"&gt;to&lt;/span&gt;p level node&lt;/span&gt;&lt;br /&gt;        Geo:=Node.GetFirstChildElement(&lt;span class="str"&gt;'GeoAddress'&lt;/span&gt;);                                              &lt;span class="rem"&gt;//get the first GeoAddress&lt;/span&gt;&lt;br /&gt;        &lt;span class="kwrd"&gt;while&lt;/span&gt; Geo&amp;lt;&amp;gt;nil &lt;span class="kwrd"&gt;do&lt;/span&gt;                                                                          &lt;span class="rem"&gt;//while we have a GeoAddress&lt;/span&gt;&lt;br /&gt;           &lt;span class="kwrd"&gt;begin&lt;/span&gt;&lt;br /&gt;           fReturnedAddresses.Add(TReturnedAddy.Create(SafeGetNodeValue(Geo, &lt;span class="str"&gt;'Street'&lt;/span&gt;),            &lt;span class="rem"&gt;//addy&lt;/span&gt;&lt;br /&gt;                                                       SafeGetNodeValue(Geo, &lt;span class="str"&gt;'AdminArea5'&lt;/span&gt;),        &lt;span class="rem"&gt;//city&lt;/span&gt;&lt;br /&gt;                                                       SafeGetNodeValue(Geo, &lt;span class="str"&gt;'AdminArea3'&lt;/span&gt;),        &lt;span class="rem"&gt;//state&lt;/span&gt;&lt;br /&gt;                                                       SafeGetNodeValue(Geo, &lt;span class="str"&gt;'PostalCode'&lt;/span&gt;),        &lt;span class="rem"&gt;//zip&lt;/span&gt;&lt;br /&gt;                                                       SafeGetNodeValue(Geo, &lt;span class="str"&gt;'AdminArea1'&lt;/span&gt;),        &lt;span class="rem"&gt;//country&lt;/span&gt;&lt;br /&gt;                                                       SafeGetNodeValue(Geo, &lt;span class="str"&gt;'AdminArea4'&lt;/span&gt;),        &lt;span class="rem"&gt;//county&lt;/span&gt;&lt;br /&gt;                                                       SafeGetSubNodeValue(Geo, &lt;span class="str"&gt;'LatLng'&lt;/span&gt;, &lt;span class="str"&gt;'Lat'&lt;/span&gt;),  &lt;span class="rem"&gt;//Latitude&lt;/span&gt;&lt;br /&gt;                                                       SafeGetSubNodeValue(Geo, &lt;span class="str"&gt;'LatLng'&lt;/span&gt;, &lt;span class="str"&gt;'Lng'&lt;/span&gt;)   &lt;span class="rem"&gt;//Longitude&lt;/span&gt;&lt;br /&gt;                                                       ));&lt;br /&gt;           Geo:=Geo.NextSibling;                                                                   &lt;span class="rem"&gt;//get the next GeoAddress&lt;/span&gt;&lt;br /&gt;           &lt;span class="kwrd"&gt;end&lt;/span&gt;;&lt;br /&gt;     &lt;span class="kwrd"&gt;finally&lt;/span&gt;&lt;br /&gt;        XML.Free;                                                                                  &lt;span class="rem"&gt;//free the XML document&lt;/span&gt;&lt;br /&gt;     &lt;span class="kwrd"&gt;end&lt;/span&gt;;&lt;br /&gt;   &lt;span class="kwrd"&gt;finally&lt;/span&gt;&lt;br /&gt;      DOM.Free;                                                                                    &lt;span class="rem"&gt;//free the dom&lt;/span&gt;&lt;br /&gt;      DOC.Free;                                                                                    &lt;span class="rem"&gt;//free the xml parser&lt;/span&gt;&lt;br /&gt;   &lt;span class="kwrd"&gt;end&lt;/span&gt;;&lt;br /&gt;&lt;span class="kwrd"&gt;end&lt;/span&gt;;&lt;br /&gt;&lt;br /&gt;{ TReturnedAddy }&lt;br /&gt;&lt;br /&gt;&lt;span class="rem"&gt;//create the object and initialize the data&lt;/span&gt;&lt;br /&gt;&lt;span class="kwrd"&gt;constructor&lt;/span&gt; TReturnedAddy.Create(aAddress, aCity, aState, aPostalCode, aCountry, aCounty, aLat, aLong: &lt;span class="kwrd"&gt;string&lt;/span&gt;);&lt;br /&gt;&lt;span class="kwrd"&gt;begin&lt;/span&gt;&lt;br /&gt;Address:=aAddress;&lt;br /&gt;City:=aCity;&lt;br /&gt;State:=aState;&lt;br /&gt;PostalCode:=aPostalCode;&lt;br /&gt;Country:=aCountry;&lt;br /&gt;County:=aCounty;&lt;br /&gt;Lat:=aLat;&lt;br /&gt;Long:=aLong;&lt;br /&gt;&lt;span class="kwrd"&gt;end&lt;/span&gt;;&lt;br /&gt;&lt;br /&gt;{ TReturnedAddyList }&lt;br /&gt;&lt;br /&gt;&lt;span class="rem"&gt;//easy way &lt;span class="kwrd"&gt;to&lt;/span&gt; get access &lt;span class="kwrd"&gt;to&lt;/span&gt; the accumulated returned addresses&lt;/span&gt;&lt;br /&gt;&lt;span class="kwrd"&gt;function&lt;/span&gt; TReturnedAddyList.getAddy(index: integer): TReturnedAddy;&lt;br /&gt;&lt;span class="kwrd"&gt;begin&lt;/span&gt;&lt;br /&gt;result:=TReturnedAddy(Items[index]);&lt;br /&gt;&lt;span class="kwrd"&gt;end&lt;/span&gt;;&lt;br /&gt;&lt;br /&gt;&lt;span class="kwrd"&gt;end&lt;/span&gt;.&lt;/pre&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/6458454884392032777-9085429063360370536?l=ruminatedrumblings.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://ruminatedrumblings.blogspot.com/feeds/9085429063360370536/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=6458454884392032777&amp;postID=9085429063360370536' title='2 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/6458454884392032777/posts/default/9085429063360370536'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/6458454884392032777/posts/default/9085429063360370536'/><link rel='alternate' type='text/html' href='http://ruminatedrumblings.blogspot.com/2008/08/mapquest-and-delphi.html' title='MapQuest and Delphi'/><author><name>Marshall Fryman</name><uri>http://www.blogger.com/profile/02996248168525053524</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>2</thr:total></entry><entry><id>tag:blogger.com,1999:blog-6458454884392032777.post-5474306898000927957</id><published>2008-08-12T10:34:00.000-07:00</published><updated>2008-08-12T11:32:24.330-07:00</updated><title type='text'>Delphi in the workgroup</title><content type='html'>Serge Dosyukov &lt;a href="http://blog.dragonsoft.us/2008/08/12/delphi-2009-beta-installation-improvements/"&gt;recently posted&lt;/a&gt; about the speed of the Delphi installer. While I agree that it's annoying to have to wait for the initial installation, I find that one of the largest failures in most development environments (including Delphi) is uniformity in a group setting. &lt;br /&gt;&lt;br /&gt;For some reason, you can use products like subversion to manage your source code, but there is no product to standardize and manage your development environment. In our case, we have a handful of developers who all are working on different aspects of a large application (&gt;1 million lines of code). We need to be able to manage the third-party add-ons and Delphi patches in a uniform way. The only method of doing this (to my knowledge) is to carefully install everything in the same paths and, usually, same order.&lt;br /&gt;&lt;br /&gt;At one point I thought we could be clever and tried to install all add-ons to a networked drive for every workstation to minimize the amount of thrash we encounter when installing SP for the add-ons. Needless to say, that was a terrible idea. We encountered problems with locks being placed on the files which caused Delphi to either crash outright or to remove the packages that were causing the problem. It's a little disingenuous to say that it "removed the package". It prompted for the removal of the package. If we didn't, Delphi simply shut down.&lt;br /&gt;&lt;br /&gt;I think the development environments should be modeled on a source control system. I don't mind the base install with the licensing restrictions, etc., etc. Once the base install is there though, I would like to be able to connect to a source repository that actually understands Delphi, it's add-on structures, and the registry entries needed to run, and be able to sync the changes up or down. That would let me take an add-on, install it on a test machine to make sure it works, sync it and then clone it down to the workstations. Better still, once the repository is built, let me &lt;span style="font-weight:bold;"&gt;roll back&lt;/span&gt; in time to something that is stable if we discover 3 months after a SP release that project XYZ just doesn't work with that SP.&lt;br /&gt;&lt;br /&gt;If CodeGear got clever, they could setup an open API that would let the add-on vendors install to the repositories and deal with the licensing issues that everyone is concerned about. Sort of an Apple Store in an open and transparent fashion (gasp!). Obviously, you could actually set the repository system up to be a true retail presence and let the add-ons register and sell via the repository. I'm sure everyone who is using Share-It is paying a small fee anyway. Wouldn't it be a better idea to capture that fee AND make everyone's life easier at the same time?&lt;br /&gt;&lt;br /&gt;How do you handle the group environment? The last time we looked at this problem in depth we were on D7. Is there a better way in D2007?&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/6458454884392032777-5474306898000927957?l=ruminatedrumblings.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://ruminatedrumblings.blogspot.com/feeds/5474306898000927957/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=6458454884392032777&amp;postID=5474306898000927957' title='4 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/6458454884392032777/posts/default/5474306898000927957'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/6458454884392032777/posts/default/5474306898000927957'/><link rel='alternate' type='text/html' href='http://ruminatedrumblings.blogspot.com/2008/08/delphi-in-workgroup.html' title='Delphi in the workgroup'/><author><name>Marshall Fryman</name><uri>http://www.blogger.com/profile/02996248168525053524</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>4</thr:total></entry><entry><id>tag:blogger.com,1999:blog-6458454884392032777.post-2508735238755152451</id><published>2008-07-21T16:05:00.000-07:00</published><updated>2008-07-21T17:07:04.025-07:00</updated><title type='text'>Indy and HTTPS Post</title><content type='html'>I'm back to work on the HTTPS Post issue with DHL's ShipIt XML API. The problem I'm having is when I use Indy to post the xml via an HTTPS post, the response is that the file is malformed. I should mention that I'm using a relatively recent version of Indy 10. If I use FF (if you don't have it, check out the Poster add-on, let's you play with the HTTP functions using FF's libraries) it works fine. The first problem is that it's a little hard to see what FF is actually doing that is different from what Indy is doing. Enter &lt;a href="http://www.fiddler2.com"&gt;Fiddler&lt;/a&gt;, stage right. Fiddler is an http proxy that captures that http information and lets you manipulate it or display the raw headers. So, pointing FF to the localhost proxy on port 8888, the headers I get are:&lt;br /&gt;&lt;br /&gt;&lt;pre class="csharpcode"&gt;&lt;br /&gt;&lt;span class="str"&gt;&lt;br /&gt;POST /apilandingtest.asp HTTP/1.1&lt;br /&gt;Host: ecommerce.airborne.com&lt;br /&gt;User-Agent: Mozilla/5.0 (Windows; U; Windows NT 6.0; en-US; rv:1.9.0.1) Gecko/2008070208 Firefox/3.0.1&lt;br /&gt;Accept: text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8&lt;br /&gt;Accept-Language: en-us,en;q=0.5&lt;br /&gt;Accept-Encoding: gzip,deflate&lt;br /&gt;Accept-Charset: ISO-8859-1,utf-8;q=0.7,*;q=0.7&lt;br /&gt;Keep-Alive: 300&lt;br /&gt;Connection: keep-alive&lt;br /&gt;Content-Type: text/xml&lt;br /&gt;Content-Length: 1509&lt;br /&gt;Pragma: no-cache&lt;br /&gt;Cache-Control: no-cache&lt;br /&gt;&lt;/span&gt;&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;Applying a TIdLogFile to the Indy HTTP IO Intercept provides Indy's headers of:&lt;br /&gt;&lt;br /&gt;&lt;pre class="csharpcode"&gt;&lt;br /&gt;&lt;span class="str"&gt;&lt;br /&gt;POST /apilandingtest.asp HTTP/1.0&lt;br /&gt;Content-Type: multipart/form-data; boundary=--------072108153606968&lt;br /&gt;Content-Length: 1662&lt;br /&gt;Host: ecommerce.airborne.com:443&lt;br /&gt;Accept: text/html, */*&lt;br /&gt;Accept-Encoding: identity&lt;br /&gt;User-Agent: Mozilla/3.0 (compatible; Indy Library)&lt;br /&gt;&lt;br /&gt;----------072108153606968&lt;br /&gt;Content-Disposition: form-data; name="Shipment"; filename="dhl.xml"&lt;br /&gt;Content-Type: text/xml&lt;br /&gt;&lt;/span&gt;&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;Obviously, not the same. A large part of this is because I'm using the TidMultiPartFormData class to encapsulate the data. Changing over to just a plain TStringList results in headers of :&lt;br /&gt;&lt;br /&gt;&lt;pre class="csharpcode"&gt;&lt;br /&gt;&lt;span class="str"&gt;&lt;br /&gt;POST /apilandingtest.asp HTTP/1.0&lt;br /&gt;Content-Type: text/xml&lt;br /&gt;Content-Length: 1471&lt;br /&gt;Host: ecommerce.airborne.com:443&lt;br /&gt;Accept: text/html, */*&lt;br /&gt;Accept-Encoding: identity&lt;br /&gt;User-Agent: Mozilla/3.0 (compatible; Indy Library)&lt;br /&gt;&lt;/span&gt;&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;but DHL still won't take the file, responding again that the XML is malformed. Looking into the log a little more, it appears as if the HTTP Post converted all CR/LF pairs into the symbol &amp;. Sure enough, in Indy's code, there is a converter that converted CR/LF to &amp;. Stripping CR/LF pairs out of the raw XML produces a workable solution that passes DHL's IIS server and returns the correct response. Obviously, that's a bit of a poor solution since it leaves the XML mashed together and I tend to use a text editor to review my XML data more often than an XML editor. So, with a short bit of preprocess work that converts CR/LF pairs to spaces, I now have a working Indy SSL HTTPS Post routine that DHL will accept. I've posted the code below so you won't have to go digging all over creation for a sample of Indy 10's HTTPS Post. Enjoy!&lt;br /&gt;&lt;br /&gt;&lt;!-- code formatted by http://manoli.net/csharpformat/ --&gt;&lt;br /&gt;&lt;pre class="csharpcode"&gt;&lt;br /&gt;&lt;span class="kwrd"&gt;const&lt;/span&gt;&lt;br /&gt;   CR = #13;&lt;br /&gt;   LF = #10;&lt;br /&gt;   EOL = CR+LF;&lt;br /&gt;   xmlEOL = EOL;&lt;br /&gt;&lt;br /&gt;&lt;span class="kwrd"&gt;type&lt;/span&gt;&lt;br /&gt;  &lt;span class="rem"&gt;// this is a desc&lt;span class="kwrd"&gt;end&lt;/span&gt;ant of TidLogFile, it will create a plain text file with&lt;/span&gt;&lt;br /&gt;  &lt;span class="rem"&gt;// information about the transfer session&lt;/span&gt;&lt;br /&gt;  TlogFile = &lt;span class="kwrd"&gt;class&lt;/span&gt;(TidLogFile)&lt;br /&gt;  &lt;span class="kwrd"&gt;protected&lt;/span&gt;&lt;br /&gt;    &lt;span class="kwrd"&gt;procedure&lt;/span&gt; LogReceivedData(&lt;span class="kwrd"&gt;const&lt;/span&gt; AText, AData: &lt;span class="kwrd"&gt;string&lt;/span&gt;); &lt;span class="kwrd"&gt;override&lt;/span&gt;;&lt;br /&gt;    &lt;span class="kwrd"&gt;procedure&lt;/span&gt; LogSentData(&lt;span class="kwrd"&gt;const&lt;/span&gt; AText, AData: &lt;span class="kwrd"&gt;string&lt;/span&gt;); &lt;span class="kwrd"&gt;override&lt;/span&gt;;&lt;br /&gt;    &lt;span class="kwrd"&gt;procedure&lt;/span&gt; LogStatus(&lt;span class="kwrd"&gt;const&lt;/span&gt; AText: &lt;span class="kwrd"&gt;string&lt;/span&gt;); &lt;span class="kwrd"&gt;override&lt;/span&gt;;&lt;br /&gt;  &lt;span class="kwrd"&gt;public&lt;/span&gt;&lt;br /&gt;    &lt;span class="kwrd"&gt;procedure&lt;/span&gt; LogWriteString(&lt;span class="kwrd"&gt;const&lt;/span&gt; AText: &lt;span class="kwrd"&gt;string&lt;/span&gt;); &lt;span class="kwrd"&gt;override&lt;/span&gt;;&lt;br /&gt;    &lt;span class="kwrd"&gt;class&lt;/span&gt; function buildLogLine(data, prefix: &lt;span class="kwrd"&gt;string&lt;/span&gt;) : &lt;span class="kwrd"&gt;string&lt;/span&gt;;&lt;br /&gt;  &lt;span class="kwrd"&gt;end&lt;/span&gt;;&lt;br /&gt;&lt;br /&gt;&lt;span class="rem"&gt;// this ensures the output of error and debug logs are in the same format, regardless of source&lt;/span&gt;&lt;br /&gt;&lt;span class="kwrd"&gt;class&lt;/span&gt; function TlogFile.buildLogLine(data, prefix: &lt;span class="kwrd"&gt;string&lt;/span&gt;) : &lt;span class="kwrd"&gt;string&lt;/span&gt;;&lt;br /&gt;&lt;span class="kwrd"&gt;begin&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;  data := StringReplace(data, EOL, RSLogEOL, [rfReplaceAll]);&lt;br /&gt;  data := StringReplace(data, CR,  RSLogCR,  [rfReplaceAll]);&lt;br /&gt;  data := StringReplace(data, LF,  RSLogLF,  [rfReplaceAll]);&lt;br /&gt;&lt;br /&gt;  result := FormatDateTime(&lt;span class="str"&gt;'yy/mm/dd hh:nn:ss'&lt;/span&gt;, now) + &lt;span class="str"&gt;' '&lt;/span&gt;;&lt;br /&gt;  &lt;span class="kwrd"&gt;if&lt;/span&gt; (prefix &amp;lt;&amp;gt; &lt;span class="str"&gt;''&lt;/span&gt;) &lt;span class="kwrd"&gt;then&lt;/span&gt;&lt;br /&gt;    result := result + prefix + &lt;span class="str"&gt;' '&lt;/span&gt;;&lt;br /&gt;  result := result + data + EOL;&lt;br /&gt;&lt;span class="kwrd"&gt;end&lt;/span&gt;;&lt;br /&gt;&lt;br /&gt;&lt;span class="rem"&gt;// ---------------------------------------------------------------------------&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span class="kwrd"&gt;procedure&lt;/span&gt; TlogFile.LogReceivedData(&lt;span class="kwrd"&gt;const&lt;/span&gt; AText, AData: &lt;span class="kwrd"&gt;string&lt;/span&gt;);&lt;br /&gt;&lt;span class="kwrd"&gt;begin&lt;/span&gt;&lt;br /&gt;  &lt;span class="rem"&gt;// ignore AText as it contains the date/time&lt;/span&gt;&lt;br /&gt;  LogWriteString(buildLogLine(Adata, &lt;span class="str"&gt;'&amp;lt;&amp;lt;'&lt;/span&gt;));&lt;br /&gt;&lt;span class="kwrd"&gt;end&lt;/span&gt;;&lt;br /&gt;&lt;br /&gt;&lt;span class="rem"&gt;// ---------------------------------------------------------------------------&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span class="kwrd"&gt;procedure&lt;/span&gt; TlogFile.LogSentData(&lt;span class="kwrd"&gt;const&lt;/span&gt; AText, AData: &lt;span class="kwrd"&gt;string&lt;/span&gt;);&lt;br /&gt;&lt;span class="kwrd"&gt;begin&lt;/span&gt;&lt;br /&gt;  &lt;span class="rem"&gt;// ignore AText as it contains the date/time&lt;/span&gt;&lt;br /&gt;  LogWriteString(buildLogLine(Adata, &lt;span class="str"&gt;'&amp;gt;&amp;gt;'&lt;/span&gt;));&lt;br /&gt;&lt;span class="kwrd"&gt;end&lt;/span&gt;;&lt;br /&gt;&lt;br /&gt;&lt;span class="rem"&gt;// ---------------------------------------------------------------------------&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span class="kwrd"&gt;procedure&lt;/span&gt; TlogFile.LogStatus(&lt;span class="kwrd"&gt;const&lt;/span&gt; AText: &lt;span class="kwrd"&gt;string&lt;/span&gt;);&lt;br /&gt;&lt;span class="kwrd"&gt;begin&lt;/span&gt;&lt;br /&gt;  LogWriteString(buildLogLine(AText, &lt;span class="str"&gt;'**'&lt;/span&gt;));&lt;br /&gt;&lt;span class="kwrd"&gt;end&lt;/span&gt;;&lt;br /&gt;&lt;br /&gt;&lt;span class="rem"&gt;// ---------------------------------------------------------------------------&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span class="kwrd"&gt;procedure&lt;/span&gt; TlogFile.LogWriteString(&lt;span class="kwrd"&gt;const&lt;/span&gt; AText: &lt;span class="kwrd"&gt;string&lt;/span&gt;);&lt;br /&gt;&lt;span class="kwrd"&gt;begin&lt;/span&gt;&lt;br /&gt;  &lt;span class="rem"&gt;// protected --&amp;gt; public&lt;/span&gt;&lt;br /&gt;  inherited;&lt;br /&gt;&lt;span class="kwrd"&gt;end&lt;/span&gt;;&lt;br /&gt;                                                       &lt;br /&gt;&lt;span class="rem"&gt;// ---------------------------------------------------------------------------&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span class="rem"&gt;//this will use an https post to push the data&lt;/span&gt;&lt;br /&gt;&lt;span class="kwrd"&gt;procedure&lt;/span&gt; TDHLShipment.s&lt;span class="kwrd"&gt;end&lt;/span&gt;File;&lt;br /&gt;&lt;span class="kwrd"&gt;const&lt;/span&gt; testURL   = &lt;span class="str"&gt;'https://some url that accepts data'&lt;/span&gt;; &lt;span class="rem"&gt;//replace this with the url of where you will be s&lt;span class="kwrd"&gt;end&lt;/span&gt;ing the data or s&lt;span class="kwrd"&gt;end&lt;/span&gt; it as a param&lt;/span&gt;&lt;br /&gt;      logFileName = &lt;span class="str"&gt;'j:\winprog\main\http.log'&lt;/span&gt;;     &lt;span class="rem"&gt;//the logfile name if you use the logging&lt;/span&gt;&lt;br /&gt;var&lt;br /&gt;  plainData : TStringList;                              &lt;span class="rem"&gt;//this is the unencoded data&lt;/span&gt;&lt;br /&gt;&lt;span class="rem"&gt;//  formData : TIdMultiPartFormDataStream;              //I've left this in just in case you want to see how the multi-part works&lt;/span&gt;&lt;br /&gt;  HTTP   : TidHTTP;                                     &lt;span class="rem"&gt;//going to need the HTTP object&lt;/span&gt;&lt;br /&gt;  SSLIO : TIdSSLIOHandlerSocketOpenSSL;                 &lt;span class="rem"&gt;//going to need the SSL object&lt;/span&gt;&lt;br /&gt;  response : TStringList;                               &lt;span class="rem"&gt;//this will catch the response from the server&lt;/span&gt;&lt;br /&gt;  logFile : TLogFile;                                   &lt;span class="rem"&gt;//this is the logfile and is optional but handy for debuging&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;  &lt;span class="rem"&gt;//this is because the plainData TStringList may contain CR/LF pairs. If so, HTTP Post will convert those pairs to &amp;amp; which, in my specific case, kills the data.&lt;/span&gt;&lt;br /&gt;  &lt;span class="kwrd"&gt;procedure&lt;/span&gt; ConvertCRLFToSpace;&lt;br /&gt;  &lt;span class="kwrd"&gt;begin&lt;/span&gt;&lt;br /&gt;    &lt;span class="kwrd"&gt;if&lt;/span&gt; plainData.Count &amp;gt; 1 &lt;span class="kwrd"&gt;then&lt;/span&gt;&lt;br /&gt;      &lt;span class="rem"&gt;// convert CR/LF pairs to spaces&lt;/span&gt;&lt;br /&gt;      plainData.Text := StringReplace(Trim(plainData.Text), sLineBreak, &lt;span class="str"&gt;' '&lt;/span&gt;,[rfReplaceAll]);&lt;br /&gt;  &lt;span class="kwrd"&gt;end&lt;/span&gt;;&lt;br /&gt;&lt;br /&gt;&lt;span class="kwrd"&gt;begin&lt;/span&gt;&lt;br /&gt;&lt;span class="rem"&gt;//  formData := TIdMultiPartFormDataStream.Create;          //if you wanted to s&lt;span class="kwrd"&gt;end&lt;/span&gt; multi-part data, use this instead&lt;/span&gt;&lt;br /&gt;  plainData := TStringList.Create;                          &lt;span class="rem"&gt;//My specific case wants stripped down headers and no multipart functionality&lt;/span&gt;&lt;br /&gt;  &lt;span class="kwrd"&gt;try&lt;/span&gt;&lt;br /&gt;&lt;span class="rem"&gt;//     formData.AddFile('Shipment', 'dhl.xml', 'text/xml'); //you can add a lot more detail about the file with the multi part data stream&lt;/span&gt;&lt;br /&gt;     plainData.LoadFromFile(&lt;span class="str"&gt;'dhl.xml'&lt;/span&gt;);                     &lt;span class="rem"&gt;//or you can just load up the plain file&lt;/span&gt;&lt;br /&gt;     Http:=TidHTTP.Create(nil);                             &lt;span class="rem"&gt;//create the HTTP instance&lt;/span&gt;&lt;br /&gt;     &lt;span class="kwrd"&gt;try&lt;/span&gt;&lt;br /&gt;        SSLIO:=TIdSSLIOHandlerSocketOpenSSL.Create(nil);    &lt;span class="rem"&gt;//create the SSL handler&lt;/span&gt;&lt;br /&gt;        SSLIO.SSLOptions.Method := sslvSSLv3;               &lt;span class="rem"&gt;//set the SSL mode&lt;/span&gt;&lt;br /&gt;        HTTP.ReadTimeout := 10000;                          &lt;span class="rem"&gt;//dep&lt;span class="kwrd"&gt;end&lt;/span&gt;ing on size of upload, you may need to adjust these&lt;/span&gt;&lt;br /&gt;        HTTP.ConnectTimeout := 10000;&lt;br /&gt;        HTTP.IOHandler := SSLIO;                            &lt;span class="rem"&gt;//assign the SSL handler to the HTTP IO Handler or you won't be able to interact with SSL servers&lt;/span&gt;&lt;br /&gt;        HTTP.Request.Content&lt;span class="kwrd"&gt;type&lt;/span&gt; := &lt;span class="str"&gt;'text/xml'&lt;/span&gt;;             &lt;span class="rem"&gt;//I'm doing XML, set the content &lt;span class="kwrd"&gt;type&lt;/span&gt; appropriate to your data &lt;span class="kwrd"&gt;type&lt;/span&gt;. If you used the multi-part, you probably don't need this&lt;/span&gt;&lt;br /&gt;        HTTP.HTTPOptions := []; &lt;span class="rem"&gt;//no options&lt;/span&gt;&lt;br /&gt;        logFile := TLogFile.Create(nil);                    &lt;span class="rem"&gt;//create the log file&lt;/span&gt;&lt;br /&gt;        logFile.FileName:=logFileName;                      &lt;span class="rem"&gt;//set the default log file name - NOTE: you could get fancy with this, but I normally don't use it&lt;/span&gt;&lt;br /&gt;        logFile.Active:=&lt;span class="kwrd"&gt;true&lt;/span&gt;;                               &lt;span class="rem"&gt;//activate the log file (creates the file and intializes everything)&lt;/span&gt;&lt;br /&gt;        HTTP.IOHandler.Intercept := logFile;                &lt;span class="rem"&gt;//set the logFile to the intercept of the IOHandler to capture the events&lt;/span&gt;&lt;br /&gt;        response:=TStringList.Create;                       &lt;span class="rem"&gt;//create the string list to catch the server's response&lt;/span&gt;&lt;br /&gt;        &lt;span class="kwrd"&gt;try&lt;/span&gt;&lt;br /&gt;           &lt;span class="kwrd"&gt;try&lt;/span&gt;&lt;br /&gt;              ConvertCRLFToSpace;                           &lt;span class="rem"&gt;//clean up the CR/LFs so the data doesn't get funky (you may not need this)&lt;/span&gt;&lt;br /&gt;              response.Text := HTTP.Post(testURL, plainData); &lt;span class="rem"&gt;//post the data to the URL and place the response in the response string list&lt;/span&gt;&lt;br /&gt;           &lt;span class="kwrd"&gt;except&lt;/span&gt; on EIdOSSLCouldNotLoadSSLLibrary &lt;span class="kwrd"&gt;do&lt;/span&gt;         &lt;span class="rem"&gt;//if we have an SSL problem, this is going to be when it shows&lt;/span&gt;&lt;br /&gt;              ShowMessage(&lt;span class="str"&gt;'An error occurred loading the SSL '&lt;/span&gt;+ &lt;span class="rem"&gt;//provide a little clue although, as I mentioned yesterday, you may need to change the SSL loader to get good error messages&lt;/span&gt;&lt;br /&gt;                          &lt;span class="str"&gt;'libraries. Please make sure you '&lt;/span&gt;+&lt;br /&gt;                          &lt;span class="str"&gt;'have installed the OpenSSL '&lt;/span&gt;+&lt;br /&gt;                          &lt;span class="str"&gt;'libraries from http://www.'&lt;/span&gt;+&lt;br /&gt;                          &lt;span class="str"&gt;'openssl.org/related/binaries.html.'&lt;/span&gt;);&lt;br /&gt;           &lt;span class="kwrd"&gt;end&lt;/span&gt;;&lt;br /&gt;           response.SaveToFile(&lt;span class="str"&gt;'response.xml'&lt;/span&gt;);             &lt;span class="rem"&gt;//save the server's response (or process it or whatever you're going to do)&lt;/span&gt;&lt;br /&gt;           ShowMessage(&lt;span class="str"&gt;'Sent successfully. Response='&lt;/span&gt;+#13#10+response.Text); &lt;span class="rem"&gt;//tell the user it worked&lt;/span&gt;&lt;br /&gt;        &lt;span class="kwrd"&gt;finally&lt;/span&gt;&lt;br /&gt;           response.Free;                                   &lt;span class="rem"&gt;//free the response&lt;/span&gt;&lt;br /&gt;        &lt;span class="kwrd"&gt;end&lt;/span&gt;;&lt;br /&gt;     &lt;span class="kwrd"&gt;finally&lt;/span&gt;&lt;br /&gt;        Http.free;                                          &lt;span class="rem"&gt;//free the http object&lt;/span&gt;&lt;br /&gt;     &lt;span class="kwrd"&gt;end&lt;/span&gt;;&lt;br /&gt;  &lt;span class="kwrd"&gt;finally&lt;/span&gt;&lt;br /&gt;     plainData.Free;                                        &lt;span class="rem"&gt;//free the data&lt;/span&gt;&lt;br /&gt;     &lt;span class="rem"&gt;//formData.Free;&lt;/span&gt;&lt;br /&gt;  &lt;span class="kwrd"&gt;end&lt;/span&gt;;&lt;br /&gt;&lt;br /&gt;&lt;span class="kwrd"&gt;end&lt;/span&gt;;&lt;br /&gt;&lt;/pre&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/6458454884392032777-2508735238755152451?l=ruminatedrumblings.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://ruminatedrumblings.blogspot.com/feeds/2508735238755152451/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=6458454884392032777&amp;postID=2508735238755152451' title='7 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/6458454884392032777/posts/default/2508735238755152451'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/6458454884392032777/posts/default/2508735238755152451'/><link rel='alternate' type='text/html' href='http://ruminatedrumblings.blogspot.com/2008/07/indy-and-https-post.html' title='Indy and HTTPS Post'/><author><name>Marshall Fryman</name><uri>http://www.blogger.com/profile/02996248168525053524</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>7</thr:total></entry><entry><id>tag:blogger.com,1999:blog-6458454884392032777.post-3846219205369138529</id><published>2008-07-20T20:27:00.000-07:00</published><updated>2008-07-20T21:43:42.645-07:00</updated><title type='text'>Indy and SSL</title><content type='html'>If anyone has ever tried to get the OpenSSL libraries to work with Indy, you may have experienced a lot of pain with the process. I'm in the process of trying to develop an application for DHL's ShipIT XML Api that utilizes an HTTPS POST. The actual post code from Indy is easy&lt;br /&gt;&lt;br /&gt;&lt;pre class="csharpcode"&gt;&lt;span class="kwrd"&gt;response := HTTP.Post(url, file);&lt;/span&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;but getting the SSL side to work, especial on Vista, is painful. I should disclose here that I have yet to get the HTTPS to send the data correctly via Indy, but I did finally get OpenSSL playing with Indy under Vista.&lt;br /&gt;&lt;br /&gt;Basically, the problem stems from the fact that Indy lets you make SSL assignments that will fail at run-time and then provides very little in the way of information about the failure. This is caused by IdSSLOpenSSLHeaders.pas not having any meaningful error reporting on the OpenSSL libraries failing to load. To be clear, it does basically say "Can't load library" but that's it.&lt;br /&gt;&lt;br /&gt;To fix it, search on SafeLoadLibrary in IdSSLOpenSSLHeaders.pas. You'll find a section that basically looks like:&lt;br /&gt;&lt;br /&gt;&lt;!-- code formatted by http://manoli.net/csharpformat/ --&gt;&lt;br /&gt;&lt;pre class="csharpcode"&gt;&lt;br /&gt;  &lt;span class="kwrd"&gt;{$IFNDEF FPC}&lt;/span&gt;&lt;br /&gt;    &lt;span class="kwrd"&gt;{$IFDEF WIN32_OR_WIN64_OR_WINCE}&lt;/span&gt;&lt;br /&gt;  &lt;span class="kwrd"&gt;if&lt;/span&gt; hIdCrypto = 0 &lt;span class="kwrd"&gt;then begin&lt;/span&gt;&lt;br /&gt;    hIdCrypto := SafeLoadLibrary(SSLCLIB_DLL_name);&lt;br /&gt;  &lt;span class="kwrd"&gt;end;&lt;/span&gt;&lt;br /&gt;  &lt;span class="kwrd"&gt;if&lt;/span&gt; hIdSSL = 0 &lt;span class="kwrd"&gt;then begin&lt;/span&gt;&lt;br /&gt;    hIdSSL := SafeLoadLibrary(SSL_DLL_name);&lt;br /&gt;  &lt;span class="kwrd"&gt;end&lt;/span&gt; &lt;span class="kwrd"&gt;else&lt;/span&gt; begin&lt;br /&gt;    &lt;span class="kwrd"&gt;Exit&lt;/span&gt;;&lt;br /&gt;  &lt;span class="kwrd"&gt;end&lt;/span&gt;;&lt;br /&gt;    &lt;span class="kwrd"&gt;{$ENDIF}&lt;/span&gt;&lt;br /&gt;&lt;span class="kwrd"&gt; {$ENDIF}&lt;/span&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;What is happening here is that hIdCrypto and hIdSSL are attempting to load the OpenSSL DLLs. If this fails, there is no trap to capture the error. I recommend changing the loading to:&lt;br /&gt;&lt;br /&gt;&lt;!-- code formatted by http://manoli.net/csharpformat/ --&gt;&lt;br /&gt;&lt;pre class="csharpcode"&gt;&lt;br /&gt;  &lt;span class="kwrd"&gt;{$IFNDEF FPC}&lt;/span&gt;&lt;br /&gt;    &lt;span class="kwrd"&gt;{$IFDEF WIN32_OR_WIN64_OR_WINCE}&lt;/span&gt;&lt;br /&gt;  &lt;span class="kwrd"&gt;if&lt;/span&gt; hIdCrypto = 0 &lt;span class="kwrd"&gt;then begin&lt;/span&gt;&lt;br /&gt;    hIdCrypto := SafeLoadLibrary(SSLCLIB_DLL_name);&lt;br /&gt;    &lt;span class="kwrd"&gt;if&lt;/span&gt; hIDCrypto&lt;1 &lt;span class="kwrd"&gt;then&lt;/span&gt;&lt;br /&gt;       Windows.MessageBox(0, pansichar(&lt;span class="str"&gt;'An error occured loading '&lt;/span&gt;+SSLCLIB_DLL_name+#13#10+ErrorDefinition(getLastError)), &lt;span class="str"&gt;'Error'&lt;/span&gt;,&lt;br /&gt;                          MB_TASKMODAL+MB_SETFOREGROUND+MB_TOPMOST);&lt;br /&gt;  &lt;span class="kwrd"&gt;end&lt;/span&gt;;&lt;br /&gt;  &lt;span class="kwrd"&gt;if&lt;/span&gt; hIdSSL = 0 &lt;span class="kwrd"&gt;then begin&lt;/span&gt;&lt;br /&gt;    hIdSSL := SafeLoadLibrary(SSL_DLL_name);&lt;br /&gt;    &lt;span class="kwrd"&gt;if&lt;/span&gt; hIDSSL&lt;1 &lt;span class="kwrd"&gt;then&lt;/span&gt;&lt;br /&gt;       Windows.MessageBox(0, pansichar(&lt;span class="str"&gt;'An error occured loading '&lt;/span&gt;+SSL_DLL_name+&lt;span class="str"&gt;#13#10&lt;/span&gt;+ErrorDefinition(getLastError)), &lt;span class="str"&gt;'Error'&lt;/span&gt;,&lt;br /&gt;                          MB_TASKMODAL+MB_SETFOREGROUND+MB_TOPMOST);&lt;br /&gt;  &lt;span class="kwrd"&gt;end&lt;/span&gt; &lt;span class="kwrd"&gt;else&lt;/span&gt; &lt;span class="kwrd"&gt;begin&lt;/span&gt;&lt;br /&gt;    &lt;span class="kwrd"&gt;Exit&lt;/span&gt;;&lt;br /&gt;  &lt;span class="kwrd"&gt;end&lt;/span&gt;;&lt;br /&gt;    &lt;span class="kwrd"&gt;{$ENDIF}&lt;/span&gt;&lt;br /&gt;&lt;span class="kwrd"&gt; {$ENDIF}&lt;/span&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;Oh, you'll also need my little cheat routine called ErrorDefinition. It just takes the last Windows error (which you pass, otherwise you couldn't save it if you had some type of log that kept track of the error number and the error message) and converts it to a string. For some reason, I find error #14401 not terribly useful.&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;!-- code formatted by http://manoli.net/csharpformat/ --&gt;&lt;br /&gt;&lt;pre class="csharpcode"&gt;&lt;br /&gt;&lt;span class="kwrd"&gt;function&lt;/span&gt; ErrorDefinition(x:&lt;span class="kwrd"&gt;longint&lt;/span&gt;):&lt;span class="kwrd"&gt;string&lt;/span&gt;;&lt;br /&gt;&lt;span class="kwrd"&gt;var&lt;/span&gt; Buffer : &lt;span class="kwrd"&gt;array&lt;/span&gt;[0..255] &lt;span class="kwrd"&gt;of&lt;/span&gt; &lt;span class="kwrd"&gt;Char&lt;/span&gt;;&lt;br /&gt;&lt;br /&gt;    &lt;span class="kwrd"&gt;function&lt;/span&gt; TrimWhite(&lt;span class="kwrd"&gt;const&lt;/span&gt; S : &lt;span class="kwrd"&gt;String&lt;/span&gt;) : &lt;span class="kwrd"&gt;String&lt;/span&gt;;&lt;br /&gt;    &lt;span class="kwrd"&gt;var&lt;/span&gt;&lt;br /&gt;      i : &lt;span class="kwrd"&gt;Integer&lt;/span&gt;;&lt;br /&gt;    &lt;span class="kwrd"&gt;begin&lt;/span&gt;&lt;br /&gt;      Result := S;&lt;br /&gt;      &lt;span class="kwrd"&gt;for&lt;/span&gt; i := length(Result) &lt;span class="kwrd"&gt;downto&lt;/span&gt; 1 &lt;span class="kwrd"&gt;do&lt;/span&gt;&lt;br /&gt;        &lt;span class="kwrd"&gt;if&lt;/span&gt; Result[i] &amp;lt; &lt;span class="str"&gt;' '&lt;/span&gt; &lt;span class="kwrd"&gt;then&lt;/span&gt;&lt;br /&gt;          Result[i] := &lt;span class="str"&gt;' '&lt;/span&gt;;&lt;br /&gt;      i := pos(&lt;span class="str"&gt;'  '&lt;/span&gt;,Result);&lt;br /&gt;      &lt;span class="kwrd"&gt;while&lt;/span&gt; i &amp;lt;&amp;gt; 0 &lt;span class="kwrd"&gt;do&lt;/span&gt; &lt;span class="kwrd"&gt;begin&lt;/span&gt;&lt;br /&gt;        delete(Result,i,1);&lt;br /&gt;        i := pos(&lt;span class="str"&gt;'  '&lt;/span&gt;,Result);&lt;br /&gt;      &lt;span class="kwrd"&gt;end&lt;/span&gt;;&lt;br /&gt;    &lt;span class="kwrd"&gt;end&lt;/span&gt;;&lt;br /&gt;&lt;br /&gt;&lt;span class="kwrd"&gt;begin&lt;/span&gt;&lt;br /&gt;   result:=&lt;span class="str"&gt;''&lt;/span&gt;;&lt;br /&gt;   &lt;span class="rem"&gt;//ask for error message from OS&lt;/span&gt;&lt;br /&gt;   &lt;span class="kwrd"&gt;if&lt;/span&gt; FormatMessage(FORMAT_MESSAGE_FROM_SYSTEM,nil,abs(x),0,&lt;br /&gt;                    Buffer,255,nil) &amp;gt; 0 &lt;span class="kwrd"&gt;then&lt;/span&gt;&lt;br /&gt;      Result := TrimWhite(StrPas(Buffer));&lt;br /&gt;&lt;span class="kwrd"&gt;end;&lt;/span&gt;&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;Some of you may want to change the MessageBox function over to a raise Exception.Create... but I'll leave that to your discretion. For my purposes, I was just trying to get something that gave more details than "Unable to load". Of course, the next problem is that the error message I got was really unhelpful. In my case, the message says that there is a problem with the SideBySide configuration and to check the event viewer for the application log. Since I have no idea what a SideBySide configuration is, I check the application log to discover this message&lt;br /&gt;&lt;br /&gt;&lt;pre class="csharpcode"&gt;&lt;br /&gt; &lt;span class="str"&gt;"Activation context generation failed for "&lt;/span&gt;j:\winprog\main\ssleay32.dll&lt;span class="str"&gt;". Dependent Assembly Microsoft.VC90.CRT,processorArchitecture="&lt;/span&gt;x86&lt;span class="str"&gt;",publicKeyToken="&lt;/span&gt;1fc8b3b9a1e18e3b&lt;span class="str"&gt;",type="&lt;/span&gt;win32&lt;span class="str"&gt;",version="&lt;/span&gt;9.0.21022.8&lt;span class="str"&gt;" could not be found. Please use sxstrace.exe for detailed diagnosis."&lt;/span&gt; &lt;br /&gt;&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;Now I'm really confused. I've just installed the OpenSSL libraries via the installer. Just to make sure, I check that the SSL DLLs actually are present in the system32 directory. Just to make sure, I copy them local and still have the problem. I then download the special OpenSSL libraries that are supposed to work better with Indy and have the same results. BTW, I did use the sxstrace tool which is (remarkably) easy to use. The problem is that it points me into the SideBySide directory (c:\windows\winsxs) which doesn't look like it's designed to be edit by people. For those interested, the sxstrace tool output looks like:&lt;br /&gt;&lt;br /&gt;&lt;pre class="csharpcode"&gt;&lt;br /&gt;&lt;span class="str"&gt;"Begin Activation Context Generation.&lt;br /&gt;Input Parameter:&lt;br /&gt; Flags = 0&lt;br /&gt; ProcessorArchitecture = x86&lt;br /&gt; CultureFallBacks = en-US;en&lt;br /&gt; ManifestPath = j:\winprog\main\libeay32.dll&lt;br /&gt; AssemblyDirectory = j:\winprog\main\&lt;br /&gt; Application Config File =&lt;br /&gt;-----------------&lt;br /&gt;INFO: Parsing Manifest File j:\winprog\main\libeay32.dll.&lt;br /&gt; INFO: Manifest Definition Identity is (null).&lt;br /&gt; INFO: Reference: Microsoft.VC90.CRT,processorArchitecture="&lt;/span&gt;x86&lt;span class="str"&gt;",publicKeyToken="&lt;/span&gt;1fc8b3b9a1e18e3b&lt;span class="str"&gt;",type="&lt;/span&gt;win32&lt;span class="str"&gt;",version="&lt;/span&gt;9.0.21022.8&lt;span class="str"&gt;"&lt;br /&gt;INFO: Resolving reference Microsoft.VC90.CRT,processorArchitecture="&lt;/span&gt;x86&lt;span class="str"&gt;",publicKeyToken="&lt;/span&gt;1fc8b3b9a1e18e3b&lt;span class="str"&gt;",type="&lt;/span&gt;win32&lt;span class="str"&gt;",version="&lt;/span&gt;9.0.21022.8&lt;span class="str"&gt;".&lt;br /&gt; INFO: Resolving reference for ProcessorArchitecture x86.&lt;br /&gt;  INFO: Resolving reference for culture Neutral.&lt;br /&gt;   INFO: Applying Binding Policy.&lt;br /&gt;    INFO: No publisher policy found.&lt;br /&gt;    INFO: No binding policy redirect found.&lt;br /&gt;   INFO: Begin assembly probing.&lt;br /&gt;    INFO: Did not find the assembly in WinSxS.&lt;br /&gt;    INFO: Attempt to probe manifest at C:\Windows\assembly\GAC_32\Microsoft.VC90.CRT\9.0.21022.8__1fc8b3b9a1e18e3b\Microsoft.VC90.CRT.DLL.&lt;br /&gt;    INFO: Attempt to probe manifest at j:\winprog\main\Microsoft.VC90.CRT.DLL.&lt;br /&gt;    INFO: Attempt to probe manifest at j:\winprog\main\Microsoft.VC90.CRT.MANIFEST.&lt;br /&gt;    INFO: Attempt to probe manifest at j:\winprog\main\Microsoft.VC90.CRT\Microsoft.VC90.CRT.DLL.&lt;br /&gt;    INFO: Attempt to probe manifest at j:\winprog\main\Microsoft.VC90.CRT\Microsoft.VC90.CRT.MANIFEST.&lt;br /&gt;    INFO: Did not find manifest for culture Neutral.&lt;br /&gt;   INFO: End assembly probing.&lt;br /&gt; ERROR: Cannot resolve reference Microsoft.VC90.CRT,processorArchitecture="&lt;/span&gt;x86&lt;span class="str"&gt;",publicKeyToken="&lt;/span&gt;1fc8b3b9a1e18e3b&lt;span class="str"&gt;",type="&lt;/span&gt;win32&lt;span class="str"&gt;",version="&lt;/span&gt;9.0.21022.8&lt;span class="str"&gt;".&lt;br /&gt;ERROR: Activation Context generation failed.&lt;br /&gt;End Activation Context Generation."&lt;/span&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;At any rate, Google of course tells me that I'm missing the MS VC 9.0 RTL. This is surprising since I have MS VS 2008 installed on this machine but some digging in those folders doesn't turn up the VC90 DLLs (which, just to be fun, are actually named msvc?90.dll). At any rate, I found a link to them on Google Code, download them and put them AND the manifest file in the system32. For those of you who read the sxstrace dump better than I did, I'm sure you won't be surprised to find that this didn't do anything to fix the problem. I then copy the DLL files locally. Still nada. I finally get a clue and copy the DLLs AND the manifest file locally and voila, I can now load the OpenSSL libraries. Of course, I could have put the files and manifest in C:\Windows\assembly\GAC_32\Microsoft.VC90.CRT\9.0.21022.8__1fc8b3b9a1e18e3b\Microsoft.VC90.CRT.DLL (I think), but that folder doesn't really look like it should be adjusted via the command prompt AND I'm probably going to switch away from Indy for this project since the chances of getting this successfully deployed to hundreds of machines just went down a couple of notches.&lt;br /&gt;&lt;br /&gt;At any rate, I still haven't figured out the HTTPS Post issue yet. I can post the XML to DHL fine via FF, but the Indy code is corrupting the XML somehow. I'll post again once I get that part figured out and provide the sample code that is so lacking from the Indy project. Don't get me wrong, Indy rocks for what it does, but they could REALLY use a huge set of "for instance" samples. This blog gets 70 hits or so every week just from people looking for hints on the Indy SMTP components that I posted a while back.&lt;br /&gt;&lt;br /&gt;Oh, and WHEN did we decided "Unable to load DLL xyz" should be renamed "SideBySide Configuration"? I don't know about you, but the former is much more descriptive than the later.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/6458454884392032777-3846219205369138529?l=ruminatedrumblings.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://ruminatedrumblings.blogspot.com/feeds/3846219205369138529/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=6458454884392032777&amp;postID=3846219205369138529' title='2 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/6458454884392032777/posts/default/3846219205369138529'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/6458454884392032777/posts/default/3846219205369138529'/><link rel='alternate' type='text/html' href='http://ruminatedrumblings.blogspot.com/2008/07/indy-and-ssl.html' title='Indy and SSL'/><author><name>Marshall Fryman</name><uri>http://www.blogger.com/profile/02996248168525053524</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>2</thr:total></entry><entry><id>tag:blogger.com,1999:blog-6458454884392032777.post-3674848046748276901</id><published>2008-05-07T14:17:00.000-07:00</published><updated>2008-05-07T16:39:39.301-07:00</updated><title type='text'>Embarcadero and the future</title><content type='html'>For everyone who isn't hiding under a rock, Embarcadero has agreed to acquire CodeGear from Borland. I'm sure all of us who have been annoyed with Borland for the last 5 years are relieved that the other shoe has finally dropped.&lt;br /&gt;&lt;br /&gt;Why 5 years you ask? Let's call a spade, a spade, and say the last really good release of Delphi was Delphi 7 until Delphi 2007 hit the scenes. That comprises a 5 year window where Delphi basically floundered around trying to be things that the core audience really didn't care about in a way that hurt sales and led everyone to assume that there would not really &lt;span style="font-weight:bold;"&gt;BE&lt;/span&gt; another good version of Delphi... ever. Fortunately, Delphi 2007 came out and changed that. Not right off the bat, it did take a service pack (or two) to get things flowing relatively smoothly, but I think everyone pretty much agrees that 2007 is the version to beat now.&lt;br /&gt;&lt;br /&gt;The biggest question is probably, "What's the future of Delphi?" Not in a "Delphi sucks" sort of way. I love Delphi. It's my preferred language for any and everything. Even where it isn't quite right, I still try and cram it in. My company even wrote it's own Delphi-script library. If that isn't love, I don't know what is. What I mean by the question is really two parts : first, where are the new Delphi developers coming from and secondly, where is Delphi going?&lt;br /&gt;&lt;br /&gt;New developers are the life blood of a language. Once the language stops attracting new developers, it's pretty much dead on the vine since everyone who is currently using it will, eventually, retire and/or move on. The positioning of Delphi in Eastern European schools is a great first step to preventing this problem. I actually think that a stronger academic program, up to and including giving the software away to academics, makes a lot of sense for both Embarcadero and the community as a whole. &lt;br /&gt;&lt;br /&gt;For the second question, I realize that anyone can point to the roadmap and say, "See, this is where we're going"; however, I think that the roadmap is extremely limited and doesn't discuss, in detail, the types of things that the language really needs. Part of that is, &lt;span style="font-weight:bold;"&gt;perhaps&lt;/span&gt;, due to the formerly public nature of CodeGear. The remainder is that the language has traditionally been controlled by just one company. Not Pascal the language, but the most widely used derivative of Pascal known as Delphi.&lt;br /&gt;&lt;br /&gt;It would be interesting if Embarcadero would split the compiler (bpcc) off as an open-source project and build the libraries and IDE on top of it. That appears to be a winning strategy for Java (ala JBuilder), why not Delphi? In fact, why have multiple different IDE's at all? Why not leverage Eclipse (again, ala JBuilder), and cut a lot of development time and effort out. Isn't code reuse a good thing?&lt;br /&gt;&lt;br /&gt;Everyone always complains about open-source software because "there is no money" in it. I'm not suggesting that anything besides the compiler needs to be opened up. When I buy Delphi, I'm not really trying to gain access to the &lt;span style="font-weight:bold;"&gt;compiler&lt;/span&gt;. What I &lt;span style="font-weight:bold;"&gt;am&lt;/span&gt; interested in is the RAD IDE and the libraries (value-added) that CodeGear makes available to me. In fact, FPC as the compiler might be an interesting revision to bpcc. It covers the majority of the goals that CodeGear has on the roadmap (64-bit, multi-CPU, multi-OS) and is close to being Delphi-compatible. Regardless of open-sourcing bpcc or using fpc, an open compiler would both permit other developers to correct issues in the compiler and reassure developers that the tool they've chosen to put millions of lines of code into isn't going to die.&lt;br /&gt;&lt;br /&gt;Additionally, the language is being threatened with further fragmentation as the multi-core (or parallel) extensions are being added. If you look at the work RemObjects has done with Oxygene, you can see that the ideas they have advanced (and modifications to the core language), are both useful and straight-forward. CodeGear hasn't, to my knowledge, made public their vision of what parallel extensions they are going to offer. Allen Bauer has blogged about some of the issues, but not in the kind of depth that RemObjects has shown. Parallel extensions is a core competency that could extended Delphi to be the best option for the multi-core CPU's that we are all using and create interest in the wider development community. With an open-sourced compiler, we could have multiple contributors working to build the core language without causing the fragmentation.&lt;br /&gt;&lt;br /&gt;To further compound the issue, Delphi's fabled RAD environment should have been brought to the Web years ago in a way that makes web programming (and I'm not referring to html here) easy for everyone. For an excellent example of what I'm talking about, look at Morfik. They have a RAD environment that supports most of the Delphi-syntax (and most of the Delphi IDE functions too) that lets developers develop applications using familiar paradigms. Isn't that the whole point of buying tools? Not to spend 12 months retraining, but to buy something that makes the transition to a new environment easier.&lt;br /&gt;&lt;br /&gt;Finally, the days of Windows being the only operating system to develop for are either already over or nearing an end. If you think this is a poor prediction, consider that Microsoft has recently released software to manage Linux servers. Between Mac OS X and the various OSS (mostly *nix) platforms, the world of homogeneous software stacks is on the way out. This doesn't even consider the tiny mobile world that has developed. Palm has sold over 1 million Centro's running Palm OS. Of that market, the current incarnation of Delphi can tap exactly 0%.&lt;br /&gt;&lt;br /&gt;Hopefully, Embarcadero will bring vision and funding to Delphi (and all of CodeGears products) in a way that we haven't seen in far too long.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/6458454884392032777-3674848046748276901?l=ruminatedrumblings.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://ruminatedrumblings.blogspot.com/feeds/3674848046748276901/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=6458454884392032777&amp;postID=3674848046748276901' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/6458454884392032777/posts/default/3674848046748276901'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/6458454884392032777/posts/default/3674848046748276901'/><link rel='alternate' type='text/html' href='http://ruminatedrumblings.blogspot.com/2008/05/embarcadero-and-future.html' title='Embarcadero and the future'/><author><name>Marshall Fryman</name><uri>http://www.blogger.com/profile/02996248168525053524</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-6458454884392032777.post-4502810088363597600</id><published>2008-04-22T14:35:00.001-07:00</published><updated>2008-04-22T14:43:14.637-07:00</updated><title type='text'>Detecting Virtual PC</title><content type='html'>Adding to my previous post on detecting virtual environments, here's the code for detecting Virtual PC. Note that it's a conversion from CodeProject, the original author is &lt;a href="http://www.codeproject.com/KB/system/VmDetect.aspx"&gt;here&lt;/a&gt;. I also didn't write the conversion, I'm simply accumulating the VMM detection code here. Original credit for the conversion goes to &lt;a href="http://coding.derkeiler.com/Archive/Delphi/borland.public.delphi.language.basm/2005-03/0652.html"&gt;Dennis Pasamore&lt;/a&gt; who did the bulk of the conversion work with some assistance from Avatar Zonderatau.&lt;br /&gt;&lt;br /&gt;Code:&lt;br /&gt;&lt;!-- code formatted by http://manoli.net/csharpformat/ --&gt;&lt;br /&gt;&lt;pre class="csharpcode"&gt;&lt;br /&gt;&lt;span class="kwrd"&gt;function&lt;/span&gt; TForm1.IsRunningVirtualPC: &lt;span class="kwrd"&gt;boolean&lt;/span&gt;;&lt;br /&gt;&lt;span class="kwrd"&gt;asm&lt;/span&gt;&lt;br /&gt;  &lt;span class="kwrd"&gt;push&lt;/span&gt; ebp;&lt;br /&gt;  &lt;span class="kwrd"&gt;mov&lt;/span&gt; ebp, esp;&lt;br /&gt;&lt;br /&gt;  &lt;span class="kwrd"&gt;mov&lt;/span&gt; ecx, &lt;span class="kwrd"&gt;offset&lt;/span&gt; @exception_handler;&lt;br /&gt;&lt;br /&gt;  &lt;span class="kwrd"&gt;push&lt;/span&gt; ebx;&lt;br /&gt;  &lt;span class="kwrd"&gt;push&lt;/span&gt; ecx;&lt;br /&gt;&lt;br /&gt;  &lt;span class="kwrd"&gt;push&lt;/span&gt; dword ptr fs:[0];&lt;br /&gt;  &lt;span class="kwrd"&gt;mov&lt;/span&gt; dword ptr fs:[0], esp;&lt;br /&gt;&lt;br /&gt;  &lt;span class="kwrd"&gt;mov&lt;/span&gt; ebx, 0; &lt;span class="rem"&gt;// Flag&lt;/span&gt;&lt;br /&gt;  &lt;span class="kwrd"&gt;mov&lt;/span&gt; eax, 1; &lt;span class="rem"&gt;// VPC function number&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;  &lt;span class="rem"&gt;// call VPC&lt;/span&gt;&lt;br /&gt;  &lt;span class="kwrd"&gt;db&lt;/span&gt; $0F, $3F, $07, $0B&lt;br /&gt;&lt;br /&gt;  &lt;span class="kwrd"&gt;mov&lt;/span&gt; eax, dword ptr ss:[esp];&lt;br /&gt;  &lt;span class="kwrd"&gt;mov&lt;/span&gt; dword ptr fs:[0], eax;&lt;br /&gt;&lt;br /&gt;  &lt;span class="kwrd"&gt;add&lt;/span&gt; esp, 8;&lt;br /&gt;&lt;br /&gt;  &lt;span class="kwrd"&gt;test&lt;/span&gt; ebx, ebx;&lt;br /&gt;&lt;br /&gt;  &lt;span class="kwrd"&gt;setz&lt;/span&gt; al;&lt;br /&gt;&lt;br /&gt;  &lt;span class="kwrd"&gt;lea&lt;/span&gt; esp, dword ptr ss:[ebp-4];&lt;br /&gt;  &lt;span class="kwrd"&gt;mov&lt;/span&gt; ebx, dword ptr ss:[esp];&lt;br /&gt;  &lt;span class="kwrd"&gt;mov&lt;/span&gt; ebp, dword ptr ss:[esp+4];&lt;br /&gt;&lt;br /&gt;  &lt;span class="kwrd"&gt;add&lt;/span&gt; esp, 8;&lt;br /&gt;&lt;br /&gt;  &lt;span class="kwrd"&gt;jmp&lt;/span&gt; @ret1;&lt;br /&gt;&lt;br /&gt;@exception_handler:&lt;br /&gt;  &lt;span class="kwrd"&gt;mov&lt;/span&gt; ecx, [esp+0Ch];&lt;br /&gt;  &lt;span class="kwrd"&gt;mov&lt;/span&gt; dword ptr [ecx+0A4h], -1; &lt;span class="rem"&gt;// EBX = -1 -&amp;gt;; not running, ebx = 0 -&amp;gt; running&lt;/span&gt;&lt;br /&gt;  &lt;span class="kwrd"&gt;add&lt;/span&gt; dword ptr [ecx+0B8h], 4;  &lt;span class="rem"&gt;// -&amp;gt;; skip past the call to VPC&lt;/span&gt;&lt;br /&gt;  &lt;span class="kwrd"&gt;xor&lt;/span&gt; eax, eax;                 &lt;span class="rem"&gt;// exception is handled&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;@ret1:&lt;br /&gt;&lt;span class="kwrd"&gt;end&lt;/span&gt;;&lt;br /&gt;&lt;/pre&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/6458454884392032777-4502810088363597600?l=ruminatedrumblings.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://ruminatedrumblings.blogspot.com/feeds/4502810088363597600/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=6458454884392032777&amp;postID=4502810088363597600' title='1 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/6458454884392032777/posts/default/4502810088363597600'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/6458454884392032777/posts/default/4502810088363597600'/><link rel='alternate' type='text/html' href='http://ruminatedrumblings.blogspot.com/2008/04/detecting-virtual-pc.html' title='Detecting Virtual PC'/><author><name>Marshall Fryman</name><uri>http://www.blogger.com/profile/02996248168525053524</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>1</thr:total></entry><entry><id>tag:blogger.com,1999:blog-6458454884392032777.post-7457179210629631581</id><published>2008-04-21T13:16:00.000-07:00</published><updated>2008-04-21T17:08:59.099-07:00</updated><title type='text'>Detecting a virtualized environment</title><content type='html'>CubicDesign on delphi-talk.elists.org recently asked the question: "How do I know/detect if my software is running under Windows [or a virtual environment]?" Well, it turns out that it's a lot harder to tell than you would think. Apparently, the VM (VMware, Xen, Wine, etc.) doesn't really want you to be able to do this. At least not easily.&lt;br /&gt;&lt;br /&gt;For VMware, there is a decent little C routine called &lt;a href="http://www.trapkit.de/tools/index.html"&gt;jerry.c&lt;/a&gt; that does the trick. Jerry actually uses a simple communication channel that VMware left open. It's not 100% foolproof since the admin can change the channel, but that's not likely going to happen unless the system is specifically designed to be a honeypot. If you're running on a honeypot and still have a legitimate reason for detection, you could look at the much more complex &lt;a href="http://www.trapkit.de/tools/index.html"&gt;scoopy&lt;/a&gt; implementation which inspects how the system is actually virtualized using the SIDT CPU instruction instead of a communication channel. Another reference (red pill) is &lt;a href="http://invisiblethings.org/papers/redpill.html"&gt;here&lt;/a&gt;.&lt;br /&gt;&lt;br /&gt;For Wine, there is a special dll entry called wine_nt_to_unix_file_name that they added to NTDLL.DLL. If you use LoadLibrary and GetProcAddress, you can determine if you are under Wine simply by the entry's presence or absence. Of course, if you specifically want to know what version of Wine you're on, you have to use NTDLL_wine_get_version but that function is only available in the bleeding edge version of wine. As an interesting side note, the Jerry test above actually returns true for VMware workstation under Wine. If you really have to know Wine vs VMware, make sure you test Wine first, otherwise you'll get a false positive.&lt;br /&gt;&lt;br /&gt;For Xen, the most reliable method appears to be to use the WMI interface and get the Bios manufacturer's information. If it's Xen, then you are under some version of Xen. Since I don't have a Xen environment setup currently, I couldn't test this information. I am relying on information published &lt;a href="http://www.pvwindrivers.org/win2k3.html"&gt;here&lt;/a&gt; to make this assertion. At some point, I'll setup a Xen server and play with it.&lt;br /&gt;&lt;br /&gt;For true VM's like Xen and Vmware, you can also test against the mac address. VMware uses 00-05-69 as the lead and Xen uses 00-16-3E. To see a list of all registered Mac addresses, go &lt;a href="http://standards.ieee.org/regauth/oui/oui.txt"&gt;here&lt;/a&gt;. Keep in mind, that the VMM supports changing the MAC address so this is also easily defeated.&lt;br /&gt;&lt;br /&gt;At any rate, here's some sample code that uses the described methods to detect VMware and Wine. Enjoy!&lt;br /&gt;&lt;br /&gt;VMware:&lt;br /&gt;&lt;!-- code formatted by http://manoli.net/csharpformat/ --&gt;&lt;br /&gt;&lt;pre class="csharpcode"&gt;&lt;br /&gt;&lt;span class="rem"&gt;//credit to chitchat@lycos.jp who discovered this method and&lt;/span&gt;&lt;br /&gt;&lt;span class="rem"&gt;//checkvm + IDA Pro ;)&lt;/span&gt;&lt;br /&gt;&lt;span class="rem"&gt;//converted from C source posted on www.trapkit.de&lt;/span&gt;&lt;br /&gt;&lt;span class="kwrd"&gt;procedure&lt;/span&gt; TForm1.btnJerryClick(Sender: TObject);&lt;br /&gt;&lt;span class="kwrd"&gt;var&lt;/span&gt; a, b:cardinal;&lt;br /&gt;&lt;span class="kwrd"&gt;begin&lt;/span&gt;&lt;br /&gt;a:=0;&lt;br /&gt;&lt;span class="kwrd"&gt;try&lt;/span&gt;&lt;br /&gt;   &lt;span class="kwrd"&gt;asm&lt;/span&gt;&lt;br /&gt;      &lt;span class="kwrd"&gt;push&lt;/span&gt; eax&lt;br /&gt;      &lt;span class="kwrd"&gt;push&lt;/span&gt; ebx&lt;br /&gt;      &lt;span class="kwrd"&gt;push&lt;/span&gt; ecx&lt;br /&gt;      &lt;span class="kwrd"&gt;push&lt;/span&gt; edx&lt;br /&gt;&lt;br /&gt;      &lt;span class="kwrd"&gt;mov&lt;/span&gt; eax, &lt;span class="str"&gt;'VMXh'&lt;/span&gt;&lt;br /&gt;      &lt;span class="kwrd"&gt;mov&lt;/span&gt; ecx, &lt;span class="str"&gt;0Ah&lt;/span&gt;&lt;br /&gt;      &lt;span class="kwrd"&gt;mov&lt;/span&gt; dx, &lt;span class="str"&gt;'VX'&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;      &lt;span class="kwrd"&gt;in&lt;/span&gt; eax, dx&lt;br /&gt;&lt;br /&gt;      &lt;span class="kwrd"&gt;mov&lt;/span&gt; a, ebx&lt;br /&gt;      &lt;span class="kwrd"&gt;mov&lt;/span&gt; b, ecx&lt;br /&gt;&lt;br /&gt;      &lt;span class="kwrd"&gt;pop&lt;/span&gt; edx&lt;br /&gt;      &lt;span class="kwrd"&gt;pop&lt;/span&gt; ecx&lt;br /&gt;      &lt;span class="kwrd"&gt;pop&lt;/span&gt; ebx&lt;br /&gt;      &lt;span class="kwrd"&gt;pop&lt;/span&gt; eax&lt;br /&gt;   &lt;span class="kwrd"&gt;end&lt;/span&gt;;&lt;br /&gt;&lt;span class="kwrd"&gt;except on&lt;/span&gt; E:Exception &lt;span class="kwrd"&gt;do&lt;/span&gt; ShowMessage(E.Message);&lt;br /&gt;&lt;span class="kwrd"&gt;end&lt;/span&gt;;&lt;br /&gt;&lt;span class="kwrd"&gt;if&lt;/span&gt; a=$564D5868 then&lt;br /&gt;   &lt;span class="kwrd"&gt;begin&lt;/span&gt;&lt;br /&gt;   ShowMessage(&lt;span class="str"&gt;'In VMware'&lt;/span&gt;);&lt;br /&gt;   &lt;span class="kwrd"&gt;case&lt;/span&gt; b &lt;span class="kwrd"&gt;of&lt;/span&gt;&lt;br /&gt;   1  : ShowMessage(&lt;span class="str"&gt;'Express'&lt;/span&gt;);&lt;br /&gt;   2  : ShowMessage(&lt;span class="str"&gt;'ESX'&lt;/span&gt;);&lt;br /&gt;   3  : ShowMessage(&lt;span class="str"&gt;'GSX'&lt;/span&gt;);&lt;br /&gt;   4  : ShowMessage(&lt;span class="str"&gt;'Workstation'&lt;/span&gt;);&lt;br /&gt;   &lt;span class="kwrd"&gt;else&lt;/span&gt; ShowMessage(&lt;span class="str"&gt;'Unknown version'&lt;/span&gt;)&lt;br /&gt;   &lt;span class="kwrd"&gt;end&lt;/span&gt;;&lt;br /&gt;   &lt;span class="kwrd"&gt;end&lt;/span&gt;&lt;br /&gt;&lt;span class="kwrd"&gt;else&lt;/span&gt;&lt;br /&gt;   ShowMessage(&lt;span class="str"&gt;'Native system'&lt;/span&gt;);&lt;br /&gt;&lt;span class="kwrd"&gt;end&lt;/span&gt;;&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;Wine:&lt;br /&gt;&lt;!-- code formatted by http://manoli.net/csharpformat/ --&gt;&lt;br /&gt;&lt;pre class="csharpcode"&gt;&lt;br /&gt;&lt;span class="kwrd"&gt;function&lt;/span&gt; TForm1.IsRunningWine: &lt;span class="kwrd"&gt;boolean&lt;/span&gt;;&lt;br /&gt;&lt;span class="kwrd"&gt;var&lt;/span&gt; hnd:THandle;&lt;br /&gt;    wine_get_version: &lt;span class="kwrd"&gt;function&lt;/span&gt; : pchar; &lt;span class="rem"&gt;{$IFDEF Win32}&lt;/span&gt; stdcall; &lt;span class="rem"&gt;{$ENDIF}&lt;/span&gt;&lt;br /&gt;    wine_unix2fn: &lt;span class="kwrd"&gt;procedure&lt;/span&gt; (p1:&lt;span class="kwrd"&gt;pointer&lt;/span&gt;; p2:&lt;span class="kwrd"&gt;pointer&lt;/span&gt;); &lt;span class="rem"&gt;{$IFDEF Win32}&lt;/span&gt; stdcall; &lt;span class="rem"&gt;{$ENDIF}&lt;/span&gt;&lt;br /&gt;&lt;span class="kwrd"&gt;begin&lt;/span&gt;&lt;br /&gt;result:=&lt;span class="kwrd"&gt;false&lt;/span&gt;;&lt;br /&gt;hnd:=LoadLibrary(&lt;span class="str"&gt;'ntdll.dll'&lt;/span&gt;);&lt;br /&gt;&lt;span class="kwrd"&gt;if&lt;/span&gt; hnd&amp;gt;32 &lt;span class="kwrd"&gt;then&lt;/span&gt;&lt;br /&gt;   &lt;span class="kwrd"&gt;begin&lt;/span&gt;&lt;br /&gt;   wine_get_version:= GetProcAddress(hnd, &lt;span class="str"&gt;'wine_get_version'&lt;/span&gt;);&lt;br /&gt;   wine_unix2fn:= GetProcAddress(hnd, &lt;span class="str"&gt;'wine_nt_to_unix_file_name'&lt;/span&gt;);&lt;br /&gt;   &lt;span class="kwrd"&gt;if&lt;/span&gt; assigned(wine_get_version) or assigned(wine_unix2fn) &lt;span class="kwrd"&gt;then&lt;/span&gt;&lt;br /&gt;      result:=&lt;span class="kwrd"&gt;true&lt;/span&gt;;&lt;br /&gt;   FreeLibrary(hnd);&lt;br /&gt;   &lt;span class="kwrd"&gt;end&lt;/span&gt;;&lt;br /&gt;&lt;br /&gt;&lt;span class="kwrd"&gt;end&lt;/span&gt;;&lt;br /&gt;&lt;/pre&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/6458454884392032777-7457179210629631581?l=ruminatedrumblings.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://ruminatedrumblings.blogspot.com/feeds/7457179210629631581/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=6458454884392032777&amp;postID=7457179210629631581' title='4 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/6458454884392032777/posts/default/7457179210629631581'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/6458454884392032777/posts/default/7457179210629631581'/><link rel='alternate' type='text/html' href='http://ruminatedrumblings.blogspot.com/2008/04/detecting-virtualized-environment.html' title='Detecting a virtualized environment'/><author><name>Marshall Fryman</name><uri>http://www.blogger.com/profile/02996248168525053524</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>4</thr:total></entry><entry><id>tag:blogger.com,1999:blog-6458454884392032777.post-4087153358093846392</id><published>2008-04-15T12:15:00.000-07:00</published><updated>2008-04-15T12:32:01.916-07:00</updated><title type='text'>Calendar Conversions</title><content type='html'>Has anyone tried to convert a Western-style calendar to either the Islamic or Hebrew calendar system? I've spent a bunch of time looking for a Pascal unit to do just that so I could include Muslim and Jewish holidays in my holiday class but haven't found any great resources. I finally found some C/C++ code that did the work and converted it over to Pascal. Keeping in mind that this is still a new conversion and that I didn't write the actual conversion logic, I'm publishing the code to help other would-be calendar converters. All of the conversion algorithms (and credit for them) are from Calendrical Calculations by Nachum Dershowitz and Edward Reingold.&lt;br /&gt;&lt;br /&gt;I added the Day and Month name strings from various Google searches on things like Hebrew Month Names and Islamic Month Names, etc. I've compared the resulting output to both published calendars and to other conversion tools that do not provide their source. So far, I haven't seen any discrepancies other than some naming conventions. Apparently, Hebrew and Arab names are "open to interpretation" when you write them in Western languages. Feel free to change them to your particular dialect. Actually, I'd like to know what the differences are/could be/should be if someone wants to enlighten me. I don't speak either language and am relying on other translations to make this work.&lt;br /&gt;&lt;br /&gt;Enjoy the code. &lt;br /&gt;&lt;br /&gt;&lt;!-- code formatted by http://manoli.net/csharpformat/ --&gt;&lt;br /&gt;&lt;pre class="csharpcode"&gt;&lt;br /&gt;&lt;span class="kwrd"&gt;unit&lt;/span&gt; calconv;&lt;br /&gt;&lt;br /&gt;&lt;span class="kwrd"&gt;interface&lt;/span&gt;&lt;br /&gt;&lt;span class="rem"&gt;// The following Pascal code is translated from the Lisp code in&lt;/span&gt;&lt;br /&gt;&lt;span class="rem"&gt;// ``Calendrical Calculations'' by Nachum Dershowitz and Edward M. Reingold,&lt;/span&gt;&lt;br /&gt;&lt;span class="rem"&gt;// Software---Practice &amp;amp; Experience, vol. 20, no. 9 (September, 1990),&lt;/span&gt;&lt;br /&gt;&lt;span class="rem"&gt;// pp. 899--928.&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span class="rem"&gt;// This code is in the public domain, but any use of it&lt;/span&gt;&lt;br /&gt;&lt;span class="rem"&gt;// should acknowledge its source.&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span class="rem"&gt;// Classes GregorianDate, JulianDate, IslamicDate, and HebrewDate&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span class="rem"&gt;// Translated from C++ / Lisp sources as published by Edward Reingold&lt;/span&gt;&lt;br /&gt;&lt;span class="rem"&gt;// at http://emr.cs.iit.edu/~reingold/calendars/shtml&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span class="rem"&gt;// Pascal translation by Marshall Fryman, 2008&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span class="kwrd"&gt;uses&lt;/span&gt; sysutils;&lt;br /&gt;&lt;br /&gt;&lt;span class="kwrd"&gt;type&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;   TBaseDate = &lt;span class="kwrd"&gt;class&lt;/span&gt;&lt;br /&gt;      &lt;span class="kwrd"&gt;private&lt;/span&gt;&lt;br /&gt;         fYear:integer;&lt;br /&gt;         fMonth:integer;&lt;br /&gt;         fDay:integer;&lt;br /&gt;      &lt;span class="kwrd"&gt;public&lt;/span&gt;&lt;br /&gt;         &lt;span class="kwrd"&gt;class&lt;/span&gt; function cf_CalDateAsAbsDate(m,d,y:integer):integer; &lt;span class="kwrd"&gt;virtual&lt;/span&gt;; &lt;span class="kwrd"&gt;abstract&lt;/span&gt;;&lt;br /&gt;         &lt;span class="kwrd"&gt;class&lt;/span&gt; function DayName(d:integer):&lt;span class="kwrd"&gt;string&lt;/span&gt;; &lt;span class="kwrd"&gt;virtual&lt;/span&gt;; &lt;span class="kwrd"&gt;abstract&lt;/span&gt;;&lt;br /&gt;         &lt;span class="kwrd"&gt;class&lt;/span&gt; function LastDayOfMonth(m,y:integer):integer; &lt;span class="kwrd"&gt;virtual&lt;/span&gt;; &lt;span class="kwrd"&gt;abstract&lt;/span&gt;;&lt;br /&gt;         function CalDateAsAbsoluteDate:integer;&lt;br /&gt;         procedure AbsoluteDateToCalDate(absdate:integer); &lt;span class="kwrd"&gt;virtual&lt;/span&gt;; &lt;span class="kwrd"&gt;abstract&lt;/span&gt;;&lt;br /&gt;         property Year:integer read fYear;&lt;br /&gt;         property Month:integer read fMonth;&lt;br /&gt;         property Day:integer read fDay;&lt;br /&gt;      end;&lt;br /&gt;&lt;br /&gt;   TGregorianDate = &lt;span class="kwrd"&gt;class&lt;/span&gt;(TBaseDate)&lt;br /&gt;&lt;span class="rem"&gt;//      inherited from base&lt;/span&gt;&lt;br /&gt;&lt;span class="rem"&gt;//        fYear   : integer;   // 1...&lt;/span&gt;&lt;br /&gt;&lt;span class="rem"&gt;//        fMonth  : integer;   // 1 == January, ..., 12 == December&lt;/span&gt;&lt;br /&gt;&lt;span class="rem"&gt;//        fDay    : integer;   // 1..LastDayOfMonth(fMonth, fYear)&lt;/span&gt;&lt;br /&gt;      &lt;span class="kwrd"&gt;public&lt;/span&gt;&lt;br /&gt;        constructor Create(m,d,y:integer);   overload; { fMonth = m; fDay = d; fYear = y; }&lt;br /&gt;        constructor Create(DT:TDateTime);    overload;&lt;br /&gt;        constructor Create(absdate:integer); overload;&lt;br /&gt;        function DateAsText:&lt;span class="kwrd"&gt;string&lt;/span&gt;;&lt;br /&gt;        procedure AbsoluteDateToCalDate(absdate:integer); &lt;span class="kwrd"&gt;override&lt;/span&gt;;&lt;br /&gt;        &lt;span class="kwrd"&gt;class&lt;/span&gt; function cf_CalDateAsAbsDate(m,d,y:integer):integer; &lt;span class="kwrd"&gt;override&lt;/span&gt;;&lt;br /&gt;        &lt;span class="kwrd"&gt;class&lt;/span&gt; function DayName(d:integer):&lt;span class="kwrd"&gt;string&lt;/span&gt;; &lt;span class="kwrd"&gt;override&lt;/span&gt;;&lt;br /&gt;        &lt;span class="kwrd"&gt;class&lt;/span&gt; function MonthName(m:integer):&lt;span class="kwrd"&gt;string&lt;/span&gt;;&lt;br /&gt;        &lt;span class="kwrd"&gt;class&lt;/span&gt; function LastDayOfMonth(m,y:integer):integer; &lt;span class="kwrd"&gt;override&lt;/span&gt;;&lt;br /&gt;      end;&lt;br /&gt;&lt;br /&gt;   TJulianDate = &lt;span class="kwrd"&gt;class&lt;/span&gt;(TBaseDate)&lt;br /&gt;&lt;span class="rem"&gt;//      inherited from base&lt;/span&gt;&lt;br /&gt;&lt;span class="rem"&gt;//        int fYear;   // 1...&lt;/span&gt;&lt;br /&gt;&lt;span class="rem"&gt;//        int fMonth;  // 1 == January, ..., 12 == December&lt;/span&gt;&lt;br /&gt;&lt;span class="rem"&gt;//        int fDay;    // 1..LastDayOfMonth(fMonth, fYear)&lt;/span&gt;&lt;br /&gt;      &lt;span class="kwrd"&gt;public&lt;/span&gt;&lt;br /&gt;        constructor Create(m,d,y:integer);   overload; { fMonth = m; fDay = d; fYear = y; }&lt;br /&gt;        constructor Create(DT:TDateTime);    overload;&lt;br /&gt;        constructor Create(absdate:integer); overload;&lt;br /&gt;        procedure AbsoluteDateToCalDate(absdate:integer); &lt;span class="kwrd"&gt;override&lt;/span&gt;;&lt;br /&gt;        &lt;span class="kwrd"&gt;class&lt;/span&gt; function cf_CalDateAsAbsDate(m,d,y:integer):integer; &lt;span class="kwrd"&gt;override&lt;/span&gt;;&lt;br /&gt;        &lt;span class="kwrd"&gt;class&lt;/span&gt; function DayName(d:integer):&lt;span class="kwrd"&gt;string&lt;/span&gt;; &lt;span class="kwrd"&gt;override&lt;/span&gt;;&lt;br /&gt;        &lt;span class="kwrd"&gt;class&lt;/span&gt; function MonthName(m:integer):&lt;span class="kwrd"&gt;string&lt;/span&gt;;&lt;br /&gt;        &lt;span class="kwrd"&gt;class&lt;/span&gt; function LastDayOfMonth(m,y:integer):integer; &lt;span class="kwrd"&gt;override&lt;/span&gt;;&lt;br /&gt;      end;&lt;br /&gt;&lt;br /&gt;   TIslamicDate = &lt;span class="kwrd"&gt;class&lt;/span&gt;(TBaseDate)&lt;br /&gt;&lt;span class="rem"&gt;//      inherited from base&lt;/span&gt;&lt;br /&gt;&lt;span class="rem"&gt;//        int fYear;   // 1...&lt;/span&gt;&lt;br /&gt;&lt;span class="rem"&gt;//        int fMonth;  // 1..12 (12 in a common Year)&lt;/span&gt;&lt;br /&gt;&lt;span class="rem"&gt;//        int fDay;    // 1..LastDayOfMonth(fMonth,fYear)&lt;/span&gt;&lt;br /&gt;      &lt;span class="kwrd"&gt;public&lt;/span&gt;&lt;br /&gt;        constructor Create(m,d,y:integer);   overload; { fMonth=m; fDay=d; fYear =y; }&lt;br /&gt;        constructor Create(DT:TDateTime);    overload;&lt;br /&gt;        constructor Create(absdate:integer); overload;&lt;br /&gt;        function DateAsText:&lt;span class="kwrd"&gt;string&lt;/span&gt;;&lt;br /&gt;        procedure AbsoluteDateToCalDate(absdate:integer); &lt;span class="kwrd"&gt;override&lt;/span&gt;;&lt;br /&gt;        &lt;span class="kwrd"&gt;class&lt;/span&gt; function cf_CalDateAsAbsDate(m,d,y:integer):integer; &lt;span class="kwrd"&gt;override&lt;/span&gt;;&lt;br /&gt;        &lt;span class="kwrd"&gt;class&lt;/span&gt; function DayName(d:integer):&lt;span class="kwrd"&gt;string&lt;/span&gt;; &lt;span class="kwrd"&gt;override&lt;/span&gt;;&lt;br /&gt;        &lt;span class="kwrd"&gt;class&lt;/span&gt; function MonthName(m:integer):&lt;span class="kwrd"&gt;string&lt;/span&gt;;&lt;br /&gt;        &lt;span class="kwrd"&gt;class&lt;/span&gt; function LastDayOfMonth(m,y:integer):integer; &lt;span class="kwrd"&gt;override&lt;/span&gt;;&lt;br /&gt;        &lt;span class="kwrd"&gt;class&lt;/span&gt; function IsLeapYear(y:integer):boolean;&lt;br /&gt;   end;&lt;br /&gt;&lt;br /&gt;   THebrewDate = &lt;span class="kwrd"&gt;class&lt;/span&gt;(TBaseDate)&lt;br /&gt;&lt;span class="rem"&gt;//      inherited from base&lt;/span&gt;&lt;br /&gt;&lt;span class="rem"&gt;//        int fYear;   // 1...&lt;/span&gt;&lt;br /&gt;&lt;span class="rem"&gt;//        int fMonth;  // 1..LastMonthOfYear(fYear)&lt;/span&gt;&lt;br /&gt;&lt;span class="rem"&gt;//        int fDay;    // 1..LastDayOfMonth(fMonth, fYear)&lt;/span&gt;&lt;br /&gt;        constructor Create(m,d,y:integer);   overload; { fMonth=m; fDay=d; fYear =y; }&lt;br /&gt;        constructor Create(DT:TDateTime);    overload;&lt;br /&gt;        constructor Create(absdate:integer); overload;&lt;br /&gt;        function DateAsText:&lt;span class="kwrd"&gt;string&lt;/span&gt;;&lt;br /&gt;        procedure AbsoluteDateToCalDate(absdate:integer); &lt;span class="kwrd"&gt;override&lt;/span&gt;;&lt;br /&gt;        &lt;span class="kwrd"&gt;class&lt;/span&gt; function cf_CalDateAsAbsDate(m,d,y:integer):integer; &lt;span class="kwrd"&gt;override&lt;/span&gt;;&lt;br /&gt;        &lt;span class="kwrd"&gt;class&lt;/span&gt; function DayName(d:integer):&lt;span class="kwrd"&gt;string&lt;/span&gt;; &lt;span class="kwrd"&gt;override&lt;/span&gt;;&lt;br /&gt;        &lt;span class="kwrd"&gt;class&lt;/span&gt; function MonthName(m,y:integer):&lt;span class="kwrd"&gt;string&lt;/span&gt;;&lt;br /&gt;        &lt;span class="kwrd"&gt;class&lt;/span&gt; function LastDayOfMonth(m,y:integer):integer; &lt;span class="kwrd"&gt;override&lt;/span&gt;;&lt;br /&gt;        &lt;span class="kwrd"&gt;class&lt;/span&gt; function IsLeapYear(y:integer):boolean;&lt;br /&gt;        &lt;span class="kwrd"&gt;class&lt;/span&gt; function LastMonthOfYear(y:integer):integer;&lt;br /&gt;        &lt;span class="kwrd"&gt;class&lt;/span&gt; function ShortKislev(y:integer):boolean;&lt;br /&gt;        &lt;span class="kwrd"&gt;class&lt;/span&gt; function LongHeshvan(y:integer):boolean;&lt;br /&gt;        &lt;span class="kwrd"&gt;class&lt;/span&gt; function DaysInYear(y:integer):integer;&lt;br /&gt;        &lt;span class="kwrd"&gt;class&lt;/span&gt; function HebrewCalendarElapsedDays(y:integer):integer;&lt;br /&gt;   end;&lt;br /&gt;&lt;br /&gt;implementation&lt;br /&gt;&lt;br /&gt;&lt;span class="rem"&gt;// Absolute dates&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span class="rem"&gt;// "Absolute date" means the number of days elapsed since the Gregorian date&lt;/span&gt;&lt;br /&gt;&lt;span class="rem"&gt;// Sunday, December 31, 1 BC. (Since there was no fYear 0, the fYear following&lt;/span&gt;&lt;br /&gt;&lt;span class="rem"&gt;// 1 BC is 1 AD.) Thus the Gregorian date January 1, 1 AD is absolute date&lt;/span&gt;&lt;br /&gt;&lt;span class="rem"&gt;// number 1.&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span class="kwrd"&gt;const&lt;/span&gt;&lt;br /&gt;   JulianEpoch = -2; &lt;span class="rem"&gt;// Absolute date of start of Julian calendar&lt;/span&gt;&lt;br /&gt;   IslamicEpoch = 227014; &lt;span class="rem"&gt;// Absolute date of start of Islamic calendar&lt;/span&gt;&lt;br /&gt;   HebrewEpoch = -1373429; &lt;span class="rem"&gt;// Absolute date of start of Hebrew calendar&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;span class="rem"&gt;// Absolute date of the x-fDay on or before absolute date d.&lt;/span&gt;&lt;br /&gt;&lt;span class="rem"&gt;// x=0 means Sunday, x=1 means Monday, and so on.&lt;/span&gt;&lt;br /&gt;function XdayOnOrBefore(d,x:integer):integer;&lt;br /&gt;begin&lt;br /&gt;  result:=(d - ((d - x) mod 7));&lt;br /&gt;end;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;{ TGregorianDate }&lt;br /&gt;&lt;br /&gt;constructor TGregorianDate.Create(m,d,y:integer);&lt;br /&gt;begin&lt;br /&gt;fMonth :=m;&lt;br /&gt;fDay   :=d;&lt;br /&gt;fYear  :=y;&lt;br /&gt;end;&lt;br /&gt;&lt;br /&gt;&lt;span class="rem"&gt;// Computes the Gregorian date from the absolute date&lt;/span&gt;&lt;br /&gt;constructor TGregorianDate.Create(absdate:integer);&lt;br /&gt;begin&lt;br /&gt;AbsoluteDateToCalDate(absdate);&lt;br /&gt;end;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;span class="rem"&gt;// Computes the absolute date from the Gregorian date.&lt;/span&gt;&lt;br /&gt;constructor TGregorianDate.Create(DT: TDateTime);&lt;br /&gt;var y,m,d:word;&lt;br /&gt;begin&lt;br /&gt;DecodeDate(DT,y,m,d);&lt;br /&gt;fYear:=y;&lt;br /&gt;fMonth:=m;&lt;br /&gt;fDay:=d;&lt;br /&gt;end;&lt;br /&gt;&lt;br /&gt;procedure TGregorianDate.AbsoluteDateToCalDate(absdate: integer);&lt;br /&gt;begin&lt;br /&gt;    &lt;span class="rem"&gt;// Search forward fYear by fYear from approximate fYear&lt;/span&gt;&lt;br /&gt;    fYear := absdate div 366;&lt;br /&gt;    &lt;span class="kwrd"&gt;while&lt;/span&gt; (absdate &amp;gt;= TGregorianDate.cf_CalDateAsAbsDate(1,1,fYear+1)) &lt;span class="kwrd"&gt;do&lt;/span&gt;&lt;br /&gt;      inc(fYear);&lt;br /&gt;    &lt;span class="rem"&gt;// Search forward fMonth by fMonth from January&lt;/span&gt;&lt;br /&gt;    fMonth := 1;&lt;br /&gt;    &lt;span class="kwrd"&gt;while&lt;/span&gt; (absdate &amp;gt; TGregorianDate.cf_CalDateAsAbsDate(fMonth, LastDayOfMonth(fMonth,fYear), fYear)) &lt;span class="kwrd"&gt;do&lt;/span&gt;&lt;br /&gt;      inc(fMonth);&lt;br /&gt;    fDay := absdate - TGregorianDate.cf_CalDateAsAbsDate(fMonth,1,fYear) + 1;&lt;br /&gt;end;&lt;br /&gt;&lt;br /&gt;&lt;span class="kwrd"&gt;class&lt;/span&gt; function TGregorianDate.cf_CalDateAsAbsDate(m,d,y:integer):integer;&lt;br /&gt;var iD,iM:integer;&lt;br /&gt;begin&lt;br /&gt;    iD := d;                                         &lt;span class="rem"&gt;// days this fMonth&lt;/span&gt;&lt;br /&gt;    &lt;span class="kwrd"&gt;for&lt;/span&gt; iM := m - 1 downto 1 &lt;span class="kwrd"&gt;do&lt;/span&gt;                      &lt;span class="rem"&gt;// days in prior months this fYear&lt;/span&gt;&lt;br /&gt;      iD := iD + LastDayOfMonth(iM, y);&lt;br /&gt;    result:=(iD                                      &lt;span class="rem"&gt;// days this fYear&lt;/span&gt;&lt;br /&gt;       + 365 * (y - 1)                               &lt;span class="rem"&gt;// days in previous years ignoring leap days&lt;/span&gt;&lt;br /&gt;       + (y - 1) div 4                               &lt;span class="rem"&gt;// Julian leap days before this fYear...&lt;/span&gt;&lt;br /&gt;       - (y - 1) div 100                             &lt;span class="rem"&gt;// ...minus prior century years...&lt;/span&gt;&lt;br /&gt;       + (y - 1) div 400);                           &lt;span class="rem"&gt;// ...plus prior years divisible by 400&lt;/span&gt;&lt;br /&gt;end;&lt;br /&gt;&lt;br /&gt;function TGregorianDate.DateAsText: &lt;span class="kwrd"&gt;string&lt;/span&gt;;&lt;br /&gt;begin&lt;br /&gt;result := DayName(CalDateAsAbsoluteDate mod 7)+&lt;span class="str"&gt;', '&lt;/span&gt;+MonthName(Month)+&lt;span class="str"&gt;' '&lt;/span&gt;+IntToStr(Day)+&lt;span class="str"&gt;', '&lt;/span&gt;+IntToStr(Year);&lt;br /&gt;end;&lt;br /&gt;&lt;br /&gt;&lt;span class="kwrd"&gt;class&lt;/span&gt; function TGregorianDate.DayName(d: integer): &lt;span class="kwrd"&gt;string&lt;/span&gt;;&lt;br /&gt;begin&lt;br /&gt;&lt;span class="kwrd"&gt;if&lt;/span&gt; d&amp;gt;6 then d:=d mod 7;&lt;br /&gt;&lt;span class="kwrd"&gt;case&lt;/span&gt; d of&lt;br /&gt;0 : result:=&lt;span class="str"&gt;'Sunday'&lt;/span&gt;;&lt;br /&gt;1 : result:=&lt;span class="str"&gt;'Monday'&lt;/span&gt;;&lt;br /&gt;2 : result:=&lt;span class="str"&gt;'Tuesday'&lt;/span&gt;;&lt;br /&gt;3 : result:=&lt;span class="str"&gt;'Wednesday'&lt;/span&gt;;&lt;br /&gt;4 : result:=&lt;span class="str"&gt;'Thursday'&lt;/span&gt;;&lt;br /&gt;5 : result:=&lt;span class="str"&gt;'Friday'&lt;/span&gt;;&lt;br /&gt;6 : result:=&lt;span class="str"&gt;'Saturday'&lt;/span&gt;;&lt;br /&gt;&lt;span class="kwrd"&gt;else&lt;/span&gt;&lt;br /&gt;   result:=&lt;span class="str"&gt;'Invalid Day'&lt;/span&gt;;&lt;br /&gt;end;&lt;br /&gt;end;&lt;br /&gt;&lt;br /&gt;&lt;span class="rem"&gt;// Compute the last date of the fMonth for the Gregorian calendar.&lt;/span&gt;&lt;br /&gt;&lt;span class="kwrd"&gt;class&lt;/span&gt; function TGregorianDate.LastDayOfMonth(m, y: integer): integer;&lt;br /&gt;begin&lt;br /&gt;  result:=31;&lt;br /&gt;  &lt;span class="kwrd"&gt;case&lt;/span&gt; m of&lt;br /&gt;   2: &lt;span class="kwrd"&gt;if&lt;/span&gt; ((((y mod 4) = 0) and ((y mod 100) &amp;lt;&amp;gt;0)) OR ((y mod 400) = 0)) then&lt;br /&gt;         result:= 29&lt;br /&gt;      &lt;span class="kwrd"&gt;else&lt;/span&gt;&lt;br /&gt;         result:= 28;&lt;br /&gt;   4,&lt;br /&gt;   6,&lt;br /&gt;   9,&lt;br /&gt;  11: result := 30;&lt;br /&gt;  end;&lt;br /&gt;end;&lt;br /&gt;&lt;br /&gt;&lt;span class="kwrd"&gt;class&lt;/span&gt; function TGregorianDate.MonthName(m: integer): &lt;span class="kwrd"&gt;string&lt;/span&gt;;&lt;br /&gt;begin&lt;br /&gt;&lt;span class="kwrd"&gt;case&lt;/span&gt; m of&lt;br /&gt;1  : result := &lt;span class="str"&gt;'January'&lt;/span&gt;;&lt;br /&gt;2  : result := &lt;span class="str"&gt;'February'&lt;/span&gt;;&lt;br /&gt;3  : result := &lt;span class="str"&gt;'March'&lt;/span&gt;;&lt;br /&gt;4  : result := &lt;span class="str"&gt;'April'&lt;/span&gt;;&lt;br /&gt;5  : result := &lt;span class="str"&gt;'May'&lt;/span&gt;;&lt;br /&gt;6  : result := &lt;span class="str"&gt;'June'&lt;/span&gt;;&lt;br /&gt;7  : result := &lt;span class="str"&gt;'July'&lt;/span&gt;;&lt;br /&gt;8  : result := &lt;span class="str"&gt;'August'&lt;/span&gt;;&lt;br /&gt;9  : result := &lt;span class="str"&gt;'September'&lt;/span&gt;;&lt;br /&gt;10 : result := &lt;span class="str"&gt;'October'&lt;/span&gt;;&lt;br /&gt;11 : result := &lt;span class="str"&gt;'November'&lt;/span&gt;;&lt;br /&gt;12 : result := &lt;span class="str"&gt;'December'&lt;/span&gt;;&lt;br /&gt;&lt;span class="kwrd"&gt;else&lt;/span&gt;&lt;br /&gt;   result:=&lt;span class="str"&gt;'Invalid Month'&lt;/span&gt;;&lt;br /&gt;end;&lt;br /&gt;end;&lt;br /&gt;&lt;br /&gt;{ TJulianDate }&lt;br /&gt;&lt;br /&gt;constructor TJulianDate.Create(m, d, y: integer);&lt;br /&gt;begin&lt;br /&gt;fmonth := m;&lt;br /&gt;fday   := d;&lt;br /&gt;fyear  := y;&lt;br /&gt;end;&lt;br /&gt;&lt;br /&gt;&lt;span class="rem"&gt;// Computes the Julian date from the absolute date.&lt;/span&gt;&lt;br /&gt;constructor TJulianDate.Create(absdate: integer);&lt;br /&gt;begin&lt;br /&gt;AbsoluteDateToCalDate(absdate);&lt;br /&gt;end;&lt;br /&gt;&lt;br /&gt;&lt;span class="rem"&gt;// Computes the absolute date from the Julian date.&lt;/span&gt;&lt;br /&gt;constructor TJulianDate.Create(DT: TDateTime);&lt;br /&gt;var gd:TGregorianDate;&lt;br /&gt;begin&lt;br /&gt;gd:=TGregorianDate.Create(DT);&lt;br /&gt;AbsoluteDateToCalDate(gd.CalDateAsAbsoluteDate);&lt;br /&gt;gd.Free;&lt;br /&gt;end;&lt;br /&gt;&lt;br /&gt;procedure TJulianDate.AbsoluteDateToCalDate(absdate: integer);&lt;br /&gt;begin&lt;br /&gt;    &lt;span class="rem"&gt;// Search forward fYear by fYear from approximate fYear&lt;/span&gt;&lt;br /&gt;    fYear := (absdate + JulianEpoch) div 366;&lt;br /&gt;    &lt;span class="kwrd"&gt;while&lt;/span&gt; (absdate &amp;gt;= TJulianDate.cf_CalDateAsAbsDate(1,1,fYear+1)) &lt;span class="kwrd"&gt;do&lt;/span&gt;&lt;br /&gt;      inc(fYear);&lt;br /&gt;    &lt;span class="rem"&gt;// Search forward fMonth by fMonth from January&lt;/span&gt;&lt;br /&gt;    fMonth := 1;&lt;br /&gt;    &lt;span class="kwrd"&gt;while&lt;/span&gt; (absdate &amp;gt; TJulianDate.cf_CalDateAsAbsDate(fMonth, LastDayOfMonth(fMonth,fYear), fYear)) &lt;span class="kwrd"&gt;do&lt;/span&gt;&lt;br /&gt;      inc(fMonth);&lt;br /&gt;    fDay := absdate - TJulianDate.cf_CalDateAsAbsDate(fMonth,1,fYear) + 1;&lt;br /&gt;end;&lt;br /&gt;&lt;br /&gt;&lt;span class="kwrd"&gt;class&lt;/span&gt; function TJulianDate.cf_CalDateAsAbsDate(m, d, y: integer): integer;&lt;br /&gt;var iD, iM:integer;&lt;br /&gt;begin&lt;br /&gt;    iD:=d;                            &lt;span class="rem"&gt;// days this Month&lt;/span&gt;&lt;br /&gt;    &lt;span class="kwrd"&gt;for&lt;/span&gt; iM:=m-1 downto 1 &lt;span class="kwrd"&gt;do&lt;/span&gt;           &lt;span class="rem"&gt;// days in prior months this Year&lt;/span&gt;&lt;br /&gt;      iD := iD + LastDayOfMonth(m, y);&lt;br /&gt;    result := (iD                     &lt;span class="rem"&gt;// days this fYear&lt;/span&gt;&lt;br /&gt;           + 365 * (y - 1)            &lt;span class="rem"&gt;// days in previous years ignoring leap days&lt;/span&gt;&lt;br /&gt;           + (y - 1) div 4            &lt;span class="rem"&gt;// leap days before this Year...&lt;/span&gt;&lt;br /&gt;           + JulianEpoch);            &lt;span class="rem"&gt;// days elapsed before absolute date 1&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;end;&lt;br /&gt;&lt;br /&gt;&lt;span class="kwrd"&gt;class&lt;/span&gt; function TJulianDate.DayName(d: integer): &lt;span class="kwrd"&gt;string&lt;/span&gt;;&lt;br /&gt;begin&lt;br /&gt;&lt;span class="kwrd"&gt;if&lt;/span&gt; d&amp;gt;6 then d:=d mod 7;&lt;br /&gt;&lt;br /&gt;&lt;span class="kwrd"&gt;case&lt;/span&gt; d of&lt;br /&gt;0 : result:=&lt;span class="str"&gt;'Sunday'&lt;/span&gt;;&lt;br /&gt;1 : result:=&lt;span class="str"&gt;'Monday'&lt;/span&gt;;&lt;br /&gt;2 : result:=&lt;span class="str"&gt;'Tuesday'&lt;/span&gt;;&lt;br /&gt;3 : result:=&lt;span class="str"&gt;'Wednesday'&lt;/span&gt;;&lt;br /&gt;4 : result:=&lt;span class="str"&gt;'Thursday'&lt;/span&gt;;&lt;br /&gt;5 : result:=&lt;span class="str"&gt;'Friday'&lt;/span&gt;;&lt;br /&gt;6 : result:=&lt;span class="str"&gt;'Saturday'&lt;/span&gt;;&lt;br /&gt;&lt;span class="kwrd"&gt;else&lt;/span&gt;&lt;br /&gt;   result:=&lt;span class="str"&gt;'Invalid Day'&lt;/span&gt;;&lt;br /&gt;end;&lt;br /&gt;end;&lt;br /&gt;&lt;br /&gt;&lt;span class="rem"&gt;// Compute the last date of the fMonth for the Julian calendar.&lt;/span&gt;&lt;br /&gt;&lt;span class="kwrd"&gt;class&lt;/span&gt; function TJulianDate.LastDayOfMonth(m, y: integer): integer;&lt;br /&gt;begin&lt;br /&gt;  &lt;span class="kwrd"&gt;case&lt;/span&gt; m of&lt;br /&gt;  2: &lt;span class="kwrd"&gt;if&lt;/span&gt; ((y mod 4) = 0) then&lt;br /&gt;       result := 29&lt;br /&gt;     &lt;span class="kwrd"&gt;else&lt;/span&gt;&lt;br /&gt;       result := 28;&lt;br /&gt;   4,&lt;br /&gt;   6,&lt;br /&gt;   9,&lt;br /&gt;   11: result := 30;&lt;br /&gt;  &lt;span class="kwrd"&gt;else&lt;/span&gt; result := 31;&lt;br /&gt;  end; {of &lt;span class="kwrd"&gt;case&lt;/span&gt;}&lt;br /&gt;end;&lt;br /&gt;&lt;br /&gt;&lt;span class="kwrd"&gt;class&lt;/span&gt; function TJulianDate.MonthName(m: integer): &lt;span class="kwrd"&gt;string&lt;/span&gt;;&lt;br /&gt;begin&lt;br /&gt;&lt;span class="kwrd"&gt;case&lt;/span&gt; m of&lt;br /&gt;1  : result := &lt;span class="str"&gt;'January'&lt;/span&gt;;&lt;br /&gt;2  : result := &lt;span class="str"&gt;'February'&lt;/span&gt;;&lt;br /&gt;3  : result := &lt;span class="str"&gt;'March'&lt;/span&gt;;&lt;br /&gt;4  : result := &lt;span class="str"&gt;'April'&lt;/span&gt;;&lt;br /&gt;5  : result := &lt;span class="str"&gt;'May'&lt;/span&gt;;&lt;br /&gt;6  : result := &lt;span class="str"&gt;'June'&lt;/span&gt;;&lt;br /&gt;7  : result := &lt;span class="str"&gt;'July'&lt;/span&gt;;&lt;br /&gt;8  : result := &lt;span class="str"&gt;'August'&lt;/span&gt;;&lt;br /&gt;9  : result := &lt;span class="str"&gt;'September'&lt;/span&gt;;&lt;br /&gt;10 : result := &lt;span class="str"&gt;'October'&lt;/span&gt;;&lt;br /&gt;11 : result := &lt;span class="str"&gt;'November'&lt;/span&gt;;&lt;br /&gt;12 : result := &lt;span class="str"&gt;'December'&lt;/span&gt;;&lt;br /&gt;&lt;span class="kwrd"&gt;else&lt;/span&gt;&lt;br /&gt;   result:=&lt;span class="str"&gt;'Invalid Month'&lt;/span&gt;;&lt;br /&gt;end;&lt;br /&gt;end;&lt;br /&gt;&lt;br /&gt;{ TIslamicDate }&lt;br /&gt;&lt;br /&gt;constructor TIslamicDate.Create(m, d, y: integer);&lt;br /&gt;begin&lt;br /&gt;fmonth := m;&lt;br /&gt;fday   := d;&lt;br /&gt;fyear  := y;&lt;br /&gt;end;&lt;br /&gt;&lt;br /&gt;&lt;span class="rem"&gt;// Computes the Islamic date from the absolute date.&lt;/span&gt;&lt;br /&gt;constructor TIslamicDate.Create(absdate: integer);&lt;br /&gt;begin&lt;br /&gt;AbsoluteDateToCalDate(absdate);&lt;br /&gt;end;&lt;br /&gt;&lt;br /&gt;procedure TIslamicDate.AbsoluteDateToCalDate(absdate: integer);&lt;br /&gt;begin&lt;br /&gt;    &lt;span class="kwrd"&gt;if&lt;/span&gt; (absdate &amp;lt;= IslamicEpoch) then &lt;span class="rem"&gt;// Date is pre-Islamic&lt;/span&gt;&lt;br /&gt;      begin&lt;br /&gt;      fMonth := 0;&lt;br /&gt;      fDay   := 0;&lt;br /&gt;      fYear  := 0;&lt;br /&gt;      end&lt;br /&gt;    &lt;span class="kwrd"&gt;else&lt;/span&gt;&lt;br /&gt;      begin&lt;br /&gt;      &lt;span class="rem"&gt;// Search forward fYear by fYear from approximate fYear&lt;/span&gt;&lt;br /&gt;      fYear := (absdate - IslamicEpoch) div 355;&lt;br /&gt;      &lt;span class="kwrd"&gt;while&lt;/span&gt; (absdate &amp;gt;= TIslamicDate.cf_CalDateAsAbsDate(1,1,fYear+1)) &lt;span class="kwrd"&gt;do&lt;/span&gt;&lt;br /&gt;        inc(fYear);&lt;br /&gt;      &lt;span class="rem"&gt;// Search forward fMonth by fMonth from Muharram&lt;/span&gt;&lt;br /&gt;      fMonth := 1;&lt;br /&gt;      &lt;span class="kwrd"&gt;while&lt;/span&gt; (absdate &amp;gt; TIslamicDate.cf_CalDateAsAbsDate(fMonth, LastDayOfMonth(fMonth,fYear), fYear)) &lt;span class="kwrd"&gt;do&lt;/span&gt;&lt;br /&gt;        inc(fMonth);&lt;br /&gt;      fDay := absdate - TIslamicDate.cf_CalDateAsAbsDate(fMonth,1,fYear) + 1;&lt;br /&gt;      end;&lt;br /&gt;end;&lt;br /&gt;&lt;br /&gt;&lt;span class="kwrd"&gt;class&lt;/span&gt; function TIslamicDate.cf_CalDateAsAbsDate(m, d, y: integer): integer;&lt;br /&gt;begin&lt;br /&gt;    result := (d                      &lt;span class="rem"&gt;// days so far this fMonth&lt;/span&gt;&lt;br /&gt;             + 29 * (m - 1)           &lt;span class="rem"&gt;// days so far...&lt;/span&gt;&lt;br /&gt;             + m div 2                &lt;span class="rem"&gt;//            ...this fYear&lt;/span&gt;&lt;br /&gt;             + 354 * (y - 1)          &lt;span class="rem"&gt;// non-leap days in prior years&lt;/span&gt;&lt;br /&gt;             + (3 + (11 * y)) div 30  &lt;span class="rem"&gt;// leap days in prior years&lt;/span&gt;&lt;br /&gt;             + IslamicEpoch);         &lt;span class="rem"&gt;// days before start of calendar&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;end;&lt;br /&gt;&lt;br /&gt;constructor TIslamicDate.Create(DT: TDateTime);&lt;br /&gt;var gd:TGregorianDate;&lt;br /&gt;begin&lt;br /&gt;gd:=TGregorianDate.Create(DT);&lt;br /&gt;AbsoluteDateToCalDate(gd.CalDateAsAbsoluteDate);&lt;br /&gt;gd.Free;&lt;br /&gt;end;&lt;br /&gt;&lt;br /&gt;function TIslamicDate.DateAsText: &lt;span class="kwrd"&gt;string&lt;/span&gt;;&lt;br /&gt;begin&lt;br /&gt;result := DayName(Day)+&lt;span class="str"&gt;', '&lt;/span&gt;+MonthName(Month)+&lt;span class="str"&gt;' '&lt;/span&gt;+IntToStr(Day)+&lt;span class="str"&gt;', '&lt;/span&gt;+IntToStr(Year);&lt;br /&gt;end;&lt;br /&gt;&lt;br /&gt;&lt;span class="kwrd"&gt;class&lt;/span&gt; function TIslamicDate.DayName(d: integer): &lt;span class="kwrd"&gt;string&lt;/span&gt;;&lt;br /&gt;begin&lt;br /&gt;&lt;span class="kwrd"&gt;if&lt;/span&gt; d&amp;gt;6 then d:=d mod 7;&lt;br /&gt;&lt;span class="kwrd"&gt;case&lt;/span&gt; d of&lt;br /&gt;0 : result := &lt;span class="str"&gt;'As-Sabt'&lt;/span&gt;;&lt;br /&gt;1 : result := &lt;span class="str"&gt;'Al-Ahad'&lt;/span&gt;;&lt;br /&gt;2 : result := &lt;span class="str"&gt;'Al-`ithnayn'&lt;/span&gt;;&lt;br /&gt;3 : result := &lt;span class="str"&gt;'Ath-Thulatha'&lt;/span&gt;;&lt;br /&gt;4 : result := &lt;span class="str"&gt;'Al-`Arba`aa'&lt;/span&gt;;&lt;br /&gt;5 : result := &lt;span class="str"&gt;'Al-Khamees'&lt;/span&gt;;&lt;br /&gt;6 : result := &lt;span class="str"&gt;'Al-Jum`ah'&lt;/span&gt;;&lt;br /&gt;&lt;span class="kwrd"&gt;else&lt;/span&gt; result:=&lt;span class="str"&gt;'Invalid Day'&lt;/span&gt;;&lt;br /&gt;end;&lt;br /&gt;end;&lt;br /&gt;&lt;br /&gt;&lt;span class="rem"&gt;// True if fYear is an Islamic leap fYear&lt;/span&gt;&lt;br /&gt;&lt;span class="kwrd"&gt;class&lt;/span&gt; function TIslamicDate.IsLeapYear(y: integer): boolean;&lt;br /&gt;begin&lt;br /&gt;  result:=((((11 * y) + 14) mod 30) &amp;lt; 11);&lt;br /&gt;end;&lt;br /&gt;&lt;br /&gt;&lt;span class="rem"&gt;// Last Day in fMonth during fYear on the Islamic calendar.&lt;/span&gt;&lt;br /&gt;&lt;span class="kwrd"&gt;class&lt;/span&gt; function TIslamicDate.LastDayOfMonth(m, y: integer): integer;&lt;br /&gt;begin&lt;br /&gt;  &lt;span class="kwrd"&gt;if&lt;/span&gt; (((m mod 2) = 1) OR ((m = 12) and IsLeapYear(y))) then&lt;br /&gt;    result:=30&lt;br /&gt;  &lt;span class="kwrd"&gt;else&lt;/span&gt;&lt;br /&gt;    result:=29;&lt;br /&gt;end;&lt;br /&gt;&lt;br /&gt;&lt;span class="kwrd"&gt;class&lt;/span&gt; function TIslamicDate.MonthName(m: integer): &lt;span class="kwrd"&gt;string&lt;/span&gt;;&lt;br /&gt;begin&lt;br /&gt;&lt;span class="kwrd"&gt;case&lt;/span&gt; m of&lt;br /&gt; 1: result := &lt;span class="str"&gt;'Muharram'&lt;/span&gt;;&lt;br /&gt; 2: result := &lt;span class="str"&gt;'Safar'&lt;/span&gt;;&lt;br /&gt; 3: result := &lt;span class="str"&gt;'Rabi`al-Awwal'&lt;/span&gt;;&lt;br /&gt; 4: result := &lt;span class="str"&gt;'Rabi`ath-Thani'&lt;/span&gt;;&lt;br /&gt; 5: result := &lt;span class="str"&gt;'Jumada l-Ula'&lt;/span&gt;;&lt;br /&gt; 6: result := &lt;span class="str"&gt;'Jumada t=Tania'&lt;/span&gt;;&lt;br /&gt; 7: result := &lt;span class="str"&gt;'Rajab'&lt;/span&gt;;&lt;br /&gt; 8: result := &lt;span class="str"&gt;'Sha`ban'&lt;/span&gt;;&lt;br /&gt; 9: result := &lt;span class="str"&gt;'Ramadan'&lt;/span&gt;;&lt;br /&gt;10: result := &lt;span class="str"&gt;'Shawwal'&lt;/span&gt;;&lt;br /&gt;11: result := &lt;span class="str"&gt;'Dhul `l-Qa`da'&lt;/span&gt;;&lt;br /&gt;12: result := &lt;span class="str"&gt;'Dhul `l-Hijja'&lt;/span&gt;;&lt;br /&gt;&lt;span class="kwrd"&gt;else&lt;/span&gt; result:=&lt;span class="str"&gt;'Invalid Month'&lt;/span&gt;;&lt;br /&gt;end;&lt;br /&gt;end;&lt;br /&gt;&lt;br /&gt;{ THebrewDate }&lt;br /&gt;&lt;br /&gt;constructor THebrewDate.Create(m, d, y: integer);&lt;br /&gt;begin&lt;br /&gt;fmonth := m;&lt;br /&gt;fday   := d;&lt;br /&gt;fyear  := y;&lt;br /&gt;end;&lt;br /&gt;&lt;br /&gt;&lt;span class="rem"&gt;// Computes the Hebrew date from the absolute date.&lt;/span&gt;&lt;br /&gt;constructor THebrewDate.Create(absdate: integer);&lt;br /&gt;begin&lt;br /&gt;AbsoluteDateToCalDate(absdate);&lt;br /&gt;end;&lt;br /&gt;&lt;br /&gt;procedure THebrewDate.AbsoluteDateToCalDate(absdate: integer);&lt;br /&gt;begin&lt;br /&gt;    fYear := (absdate + HebrewEpoch) div 366; &lt;span class="rem"&gt;// Approximation from below.&lt;/span&gt;&lt;br /&gt;    &lt;span class="rem"&gt;// Search forward for fYear from the approximation.&lt;/span&gt;&lt;br /&gt;    &lt;span class="kwrd"&gt;while&lt;/span&gt; (absdate &amp;gt;= THebrewDate.cf_CalDateAsAbsDate(7,1,fYear + 1)) &lt;span class="kwrd"&gt;do&lt;/span&gt;&lt;br /&gt;      inc(fYear);&lt;br /&gt;    &lt;span class="rem"&gt;// Search forward for month from either Tishri or Nisan.&lt;/span&gt;&lt;br /&gt;    &lt;span class="kwrd"&gt;if&lt;/span&gt; (absdate &amp;lt; THebrewDate.cf_CalDateAsAbsDate(1, 1, fYear)) then&lt;br /&gt;      fMonth := 7  &lt;span class="rem"&gt;//  Start at Tishri&lt;/span&gt;&lt;br /&gt;    &lt;span class="kwrd"&gt;else&lt;/span&gt;&lt;br /&gt;      fMonth := 1;  &lt;span class="rem"&gt;//  Start at Nisan&lt;/span&gt;&lt;br /&gt;    &lt;span class="kwrd"&gt;while&lt;/span&gt; (absdate &amp;gt; THebrewDate.cf_CalDateAsAbsDate(fMonth, (LastDayOfMonth(fMonth,fYear)), fYear)) &lt;span class="kwrd"&gt;do&lt;/span&gt;&lt;br /&gt;      inc(fMonth);&lt;br /&gt;    &lt;span class="rem"&gt;// Calculate the fDay by subtraction.&lt;/span&gt;&lt;br /&gt;    fDay := absdate - THebrewDate.cf_CalDateAsAbsDate(fMonth, 1, fYear) + 1;&lt;br /&gt;end;&lt;br /&gt;&lt;br /&gt;&lt;span class="kwrd"&gt;class&lt;/span&gt; function THebrewDate.cf_CalDateAsAbsDate(m, d, y: integer): integer;&lt;br /&gt;var DayInYear:integer;&lt;br /&gt;    iM:integer;&lt;br /&gt;begin&lt;br /&gt;    DayInYear := d; &lt;span class="rem"&gt;// Days so far this Month.&lt;/span&gt;&lt;br /&gt;    &lt;span class="kwrd"&gt;if&lt;/span&gt; (m &amp;lt; 7) then &lt;span class="rem"&gt;// Before Tishri, so add days in prior months&lt;/span&gt;&lt;br /&gt;      begin             &lt;span class="rem"&gt;// this Year before and after Nisan.&lt;/span&gt;&lt;br /&gt;      iM := 7;&lt;br /&gt;      &lt;span class="kwrd"&gt;while&lt;/span&gt; (iM &amp;lt;= (LastMonthOfYear(y))) &lt;span class="kwrd"&gt;do&lt;/span&gt;&lt;br /&gt;        begin&lt;br /&gt;        DayInYear := DayInYear + LastDayOfMonth(iM, y);&lt;br /&gt;        inc(iM);&lt;br /&gt;        end;&lt;br /&gt;      iM := 1;&lt;br /&gt;      &lt;span class="kwrd"&gt;while&lt;/span&gt; (iM &amp;lt; m) &lt;span class="kwrd"&gt;do&lt;/span&gt;&lt;br /&gt;        begin&lt;br /&gt;        DayInYear := DayInYear + LastDayOfMonth(iM, y);&lt;br /&gt;        inc(iM);&lt;br /&gt;        end;&lt;br /&gt;      end&lt;br /&gt;    &lt;span class="kwrd"&gt;else&lt;/span&gt;  &lt;span class="rem"&gt;// Add days in prior months this Year&lt;/span&gt;&lt;br /&gt;      begin&lt;br /&gt;      iM := 7;&lt;br /&gt;      &lt;span class="kwrd"&gt;while&lt;/span&gt; (iM &amp;lt; m) &lt;span class="kwrd"&gt;do&lt;/span&gt;&lt;br /&gt;        begin&lt;br /&gt;        DayInYear := DayInYear + LastDayOfMonth(iM, y);&lt;br /&gt;        inc(iM);&lt;br /&gt;        end;&lt;br /&gt;      end;&lt;br /&gt;&lt;br /&gt;    result := (DayInYear +&lt;br /&gt;              (HebrewCalendarElapsedDays(y)&lt;span class="rem"&gt;// Days in prior years.&lt;/span&gt;&lt;br /&gt;               + HebrewEpoch));            &lt;span class="rem"&gt;// Days elapsed before absolute date 1.&lt;/span&gt;&lt;br /&gt;end;&lt;br /&gt;&lt;br /&gt;constructor THebrewDate.Create(DT: TDateTime);&lt;br /&gt;var gd:TGregorianDate;&lt;br /&gt;begin&lt;br /&gt;gd:=TGregorianDate.Create(DT);&lt;br /&gt;AbsoluteDateToCalDate(gd.CalDateAsAbsoluteDate);&lt;br /&gt;gd.Free;&lt;br /&gt;end;&lt;br /&gt;&lt;br /&gt;function THebrewDate.DateAsText: &lt;span class="kwrd"&gt;string&lt;/span&gt;;&lt;br /&gt;begin&lt;br /&gt;result := DayName(Day)+&lt;span class="str"&gt;', '&lt;/span&gt;+MonthName(Month,Year)+&lt;span class="str"&gt;' '&lt;/span&gt;+IntToStr(Day)+&lt;span class="str"&gt;', '&lt;/span&gt;+IntToStr(Year);&lt;br /&gt;end;&lt;br /&gt;&lt;br /&gt;&lt;span class="kwrd"&gt;class&lt;/span&gt; function THebrewDate.DayName(d: integer): &lt;span class="kwrd"&gt;string&lt;/span&gt;;&lt;br /&gt;begin&lt;br /&gt;&lt;span class="kwrd"&gt;if&lt;/span&gt; d&amp;gt;6 then d:=d mod 7;&lt;br /&gt;&lt;span class="kwrd"&gt;case&lt;/span&gt; d of&lt;br /&gt;0 :  result := &lt;span class="str"&gt;'Yom Ree-Shoun'&lt;/span&gt;;&lt;br /&gt;1 :  result := &lt;span class="str"&gt;'Yom She-Nee'&lt;/span&gt;;&lt;br /&gt;2 :  result := &lt;span class="str"&gt;'Yom Shelee-She'&lt;/span&gt;;&lt;br /&gt;3 :  result := &lt;span class="str"&gt;'Yom Re-Ve-ee'&lt;/span&gt;;&lt;br /&gt;4 :  result := &lt;span class="str"&gt;'Yom Hah-Mee-Shee'&lt;/span&gt;;&lt;br /&gt;5 :  result := &lt;span class="str"&gt;'Yom Shee-Shee'&lt;/span&gt;;&lt;br /&gt;6 :  result := &lt;span class="str"&gt;'Yom Sha-Bat'&lt;/span&gt;;&lt;br /&gt;&lt;span class="kwrd"&gt;else&lt;/span&gt; result := &lt;span class="str"&gt;'Invalid Day'&lt;/span&gt;;&lt;br /&gt;end;&lt;br /&gt;end;&lt;br /&gt;&lt;br /&gt;&lt;span class="rem"&gt;// Number of days in Hebrew Year.&lt;/span&gt;&lt;br /&gt;&lt;span class="kwrd"&gt;class&lt;/span&gt; function THebrewDate.DaysInYear(y: integer): integer;&lt;br /&gt;begin&lt;br /&gt;  result := ((HebrewCalendarElapsedDays(y + 1)) -&lt;br /&gt;            (HebrewCalendarElapsedDays(y)));&lt;br /&gt;end;&lt;br /&gt;&lt;br /&gt;&lt;span class="rem"&gt;// Number of days elapsed from the Sunday prior to the start of the&lt;/span&gt;&lt;br /&gt;&lt;span class="rem"&gt;// Hebrew calendar to the mean conjunction of Tishri of Hebrew fYear.&lt;/span&gt;&lt;br /&gt;&lt;span class="kwrd"&gt;class&lt;/span&gt; function THebrewDate.HebrewCalendarElapsedDays(y: integer): integer;&lt;br /&gt;var MonthsElapsed,&lt;br /&gt;    PartsElapsed,&lt;br /&gt;    HoursElapsed,&lt;br /&gt;    ConjunctionDay,&lt;br /&gt;    ConjunctionParts,&lt;br /&gt;    AlternativeDay : integer;&lt;br /&gt;begin&lt;br /&gt;  MonthsElapsed :=&lt;br /&gt;    (235 * ((y - 1) div 19))           &lt;span class="rem"&gt;// Months in complete cycles so far.&lt;/span&gt;&lt;br /&gt;    + (12 * ((y - 1) mod 19))          &lt;span class="rem"&gt;// Regular months in this cycle.&lt;/span&gt;&lt;br /&gt;    + (7 * ((y - 1) mod 19) + 1) div 19; &lt;span class="rem"&gt;// Leap months this cycle&lt;/span&gt;&lt;br /&gt;  PartsElapsed := 204 + (793 * (MonthsElapsed mod 1080));&lt;br /&gt;  HoursElapsed :=&lt;br /&gt;    5 + (12 * MonthsElapsed) + (793 * (MonthsElapsed  div 1080))&lt;br /&gt;    + (PartsElapsed div 1080);&lt;br /&gt;  ConjunctionDay := 1 + (29 * MonthsElapsed) + (HoursElapsed div 24);&lt;br /&gt;  ConjunctionParts := (1080 * (HoursElapsed mod 24)) + (PartsElapsed mod 1080);&lt;br /&gt;  &lt;span class="kwrd"&gt;if&lt;/span&gt; ((ConjunctionParts &amp;gt;= 19440)         &lt;span class="rem"&gt;// If new moon is at or after midday,&lt;/span&gt;&lt;br /&gt;      OR (((ConjunctionDay mod 7) = 2)    &lt;span class="rem"&gt;// ...or is on a Tuesday...&lt;/span&gt;&lt;br /&gt;          and (ConjunctionParts &amp;gt;= 9924)  &lt;span class="rem"&gt;// at 9 hours, 204 parts or later...&lt;/span&gt;&lt;br /&gt;          and not (IsLeapYear(y)))        &lt;span class="rem"&gt;// ...of a common year,&lt;/span&gt;&lt;br /&gt;      OR (((ConjunctionDay mod 7) = 1)    &lt;span class="rem"&gt;// ...or is on a Monday at...&lt;/span&gt;&lt;br /&gt;          and (ConjunctionParts &amp;gt;= 16789) &lt;span class="rem"&gt;// 15 hours, 589 parts or later...&lt;/span&gt;&lt;br /&gt;          and (IsLeapYear(y - 1)))) then  &lt;span class="rem"&gt;// at the end of a leap year&lt;/span&gt;&lt;br /&gt;    &lt;span class="rem"&gt;// Then postpone Rosh HaShanah one Day&lt;/span&gt;&lt;br /&gt;    AlternativeDay := ConjunctionDay + 1&lt;br /&gt;  &lt;span class="kwrd"&gt;else&lt;/span&gt;&lt;br /&gt;    AlternativeDay := ConjunctionDay;&lt;br /&gt;  &lt;span class="kwrd"&gt;if&lt;/span&gt; (((AlternativeDay mod 7) = 0)          &lt;span class="rem"&gt;// If Rosh HaShanah would occur on Sunday,&lt;/span&gt;&lt;br /&gt;      OR ((AlternativeDay mod 7) = 3)       &lt;span class="rem"&gt;// or Wednesday,&lt;/span&gt;&lt;br /&gt;      OR ((AlternativeDay mod 7) = 5)) then &lt;span class="rem"&gt;// or Friday&lt;/span&gt;&lt;br /&gt;    &lt;span class="rem"&gt;// Then postpone it one (more) Day&lt;/span&gt;&lt;br /&gt;    result := (1 + AlternativeDay)&lt;br /&gt;  &lt;span class="kwrd"&gt;else&lt;/span&gt;&lt;br /&gt;    result := AlternativeDay;&lt;br /&gt;end;&lt;br /&gt;&lt;br /&gt;&lt;span class="rem"&gt;// True if y is an Hebrew leap year&lt;/span&gt;&lt;br /&gt;&lt;span class="kwrd"&gt;class&lt;/span&gt; function THebrewDate.IsLeapYear(y: integer): boolean;&lt;br /&gt;begin&lt;br /&gt;  result := ((((7 * y) + 1) mod  19) &amp;lt; 7);&lt;br /&gt;end;&lt;br /&gt;&lt;br /&gt;&lt;span class="rem"&gt;// Last fDay of Month in Hebrew Year.&lt;/span&gt;&lt;br /&gt;&lt;span class="kwrd"&gt;class&lt;/span&gt; function THebrewDate.LastDayOfMonth(m, y: integer): integer;&lt;br /&gt;begin&lt;br /&gt;  &lt;span class="kwrd"&gt;if&lt;/span&gt; ((m = 2)&lt;br /&gt;      OR (m = 4)&lt;br /&gt;      OR (m = 6)&lt;br /&gt;      OR ((m = 8) and not (LongHeshvan(y)))&lt;br /&gt;      OR ((m = 9) and ShortKislev(y))&lt;br /&gt;      OR (m = 10)&lt;br /&gt;      OR ((m = 12) and not (IsLeapYear(y)))&lt;br /&gt;      OR (m = 13)) then&lt;br /&gt;    result := 29&lt;br /&gt;  &lt;span class="kwrd"&gt;else&lt;/span&gt;&lt;br /&gt;    result:= 30;&lt;br /&gt;&lt;br /&gt;end;&lt;br /&gt;&lt;br /&gt;&lt;span class="rem"&gt;// Last Month of Hebrew Year y.&lt;/span&gt;&lt;br /&gt;&lt;span class="kwrd"&gt;class&lt;/span&gt; function THebrewDate.LastMonthOfYear(y: integer): integer;&lt;br /&gt;begin&lt;br /&gt;  &lt;span class="kwrd"&gt;if&lt;/span&gt; (IsLeapYear(y)) then&lt;br /&gt;    result := 13&lt;br /&gt;  &lt;span class="kwrd"&gt;else&lt;/span&gt;&lt;br /&gt;    result := 12;&lt;br /&gt;end;&lt;br /&gt;&lt;br /&gt;&lt;span class="rem"&gt;// True if Heshvan is long in Hebrew fYear.&lt;/span&gt;&lt;br /&gt;&lt;span class="kwrd"&gt;class&lt;/span&gt; function THebrewDate.LongHeshvan(y: integer): boolean;&lt;br /&gt;begin&lt;br /&gt;  result := ((DaysInYear(y) mod 10) = 5);&lt;br /&gt;end;&lt;br /&gt;&lt;br /&gt;&lt;span class="kwrd"&gt;class&lt;/span&gt; function THebrewDate.MonthName(m,y: integer): &lt;span class="kwrd"&gt;string&lt;/span&gt;;&lt;br /&gt;begin&lt;br /&gt;result:=&lt;span class="str"&gt;'Invalid Month'&lt;/span&gt;;&lt;br /&gt;&lt;span class="kwrd"&gt;if&lt;/span&gt; not IsLeapYear(y) then&lt;br /&gt;   &lt;span class="kwrd"&gt;case&lt;/span&gt; m of&lt;br /&gt;   1 : result := &lt;span class="str"&gt;'Nissan'&lt;/span&gt;;&lt;br /&gt;   2 : result := &lt;span class="str"&gt;'Iyar'&lt;/span&gt;;&lt;br /&gt;   3 : result := &lt;span class="str"&gt;'Sivan'&lt;/span&gt;;&lt;br /&gt;   4 : result := &lt;span class="str"&gt;'Tammuz'&lt;/span&gt;;&lt;br /&gt;   5 : result := &lt;span class="str"&gt;'Av'&lt;/span&gt;;&lt;br /&gt;   6 : result := &lt;span class="str"&gt;'Elul'&lt;/span&gt;;&lt;br /&gt;   7 : result := &lt;span class="str"&gt;'Tishrei'&lt;/span&gt;;&lt;br /&gt;   8 : result := &lt;span class="str"&gt;'Heshvan'&lt;/span&gt;;&lt;br /&gt;   9 : result := &lt;span class="str"&gt;'Kislev'&lt;/span&gt;;&lt;br /&gt;   10: result := &lt;span class="str"&gt;'Teves'&lt;/span&gt;;&lt;br /&gt;   11: result := &lt;span class="str"&gt;'Shevat'&lt;/span&gt;;&lt;br /&gt;   12: result := &lt;span class="str"&gt;'Adar'&lt;/span&gt;;&lt;br /&gt;   end&lt;br /&gt;&lt;span class="kwrd"&gt;else&lt;/span&gt;&lt;br /&gt;   &lt;span class="kwrd"&gt;case&lt;/span&gt; m of&lt;br /&gt;   1 : result := &lt;span class="str"&gt;'Nissan'&lt;/span&gt;;&lt;br /&gt;   2 : result := &lt;span class="str"&gt;'Iyar'&lt;/span&gt;;&lt;br /&gt;   3 : result := &lt;span class="str"&gt;'Sivan'&lt;/span&gt;;&lt;br /&gt;   4 : result := &lt;span class="str"&gt;'Tammuz'&lt;/span&gt;;&lt;br /&gt;   5 : result := &lt;span class="str"&gt;'Av'&lt;/span&gt;;&lt;br /&gt;   6 : result := &lt;span class="str"&gt;'Elul'&lt;/span&gt;;&lt;br /&gt;   7 : result := &lt;span class="str"&gt;'Tishrei'&lt;/span&gt;;&lt;br /&gt;   8 : result := &lt;span class="str"&gt;'Heshvan'&lt;/span&gt;;&lt;br /&gt;   9 : result := &lt;span class="str"&gt;'Kislev'&lt;/span&gt;;&lt;br /&gt;   10: result := &lt;span class="str"&gt;'Teves'&lt;/span&gt;;&lt;br /&gt;   11: result := &lt;span class="str"&gt;'Shevat'&lt;/span&gt;;&lt;br /&gt;   12: result := &lt;span class="str"&gt;'Adar I'&lt;/span&gt;;&lt;br /&gt;   13: result := &lt;span class="str"&gt;'Adar II'&lt;/span&gt;;&lt;br /&gt;   end&lt;br /&gt;end;&lt;br /&gt;&lt;br /&gt;&lt;span class="rem"&gt;// True if Kislev is short in Hebrew fYear.&lt;/span&gt;&lt;br /&gt;&lt;span class="kwrd"&gt;class&lt;/span&gt; function THebrewDate.ShortKislev(y: integer): boolean;&lt;br /&gt;begin&lt;br /&gt;  result := ((DaysInYear(y) mod 10) = 3);&lt;br /&gt;end;&lt;br /&gt;&lt;br /&gt;{ TBaseDate }&lt;br /&gt;&lt;br /&gt;function TBaseDate.CalDateAsAbsoluteDate: integer;&lt;br /&gt;begin&lt;br /&gt;result := self.cf_CalDateAsAbsDate(Month,Day,Year);&lt;br /&gt;end;&lt;br /&gt;&lt;br /&gt;end.&lt;/pre&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/6458454884392032777-4087153358093846392?l=ruminatedrumblings.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://ruminatedrumblings.blogspot.com/feeds/4087153358093846392/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=6458454884392032777&amp;postID=4087153358093846392' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/6458454884392032777/posts/default/4087153358093846392'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/6458454884392032777/posts/default/4087153358093846392'/><link rel='alternate' type='text/html' href='http://ruminatedrumblings.blogspot.com/2008/04/calendar-conversions.html' title='Calendar Conversions'/><author><name>Marshall Fryman</name><uri>http://www.blogger.com/profile/02996248168525053524</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-6458454884392032777.post-7214315275639670210</id><published>2008-04-08T16:41:00.001-07:00</published><updated>2008-04-08T17:59:54.384-07:00</updated><title type='text'>SMTP Mail and Indy (again)</title><content type='html'>Having spent a lot of time recently working on a ping scanner using Indy, I noticed that there's a lot of questions still on using SMTP with Indy. Let me first say that I am not an Indy expert. I get along with it successfully but find I still have to research things frequently.&lt;br /&gt;&lt;br /&gt;With the disclaimer out of the way, we can get to the offering. A while back I wrote a handy little unit to simply send a mail message with or without attachments and with or without providing authentication. It even has support for OpenSSL. I use this unit in a number of applications and have seen it successfully send hundreds of e-mails without issue. I recently added support for threaded message sending to take advantage of the multi-core system I'm now running on.&lt;br /&gt;&lt;br /&gt;This code has had a few additions (like the logger) that I've gleaned over time from various newsgroup postings, but I didn't record the authors so let me credit the anonymous Internet authors who support Indy. It's really amazing how helpful Google can be when you're stuck. At any rate, here's the code for the mailer in the hopes that it will help someone else who is stuck dealing with SMTP.&lt;br /&gt;&lt;br /&gt;&lt;!-- code formatted by http://manoli.net/csharpformat/ --&gt;&lt;br /&gt;&lt;pre class="csharpcode"&gt;&lt;br /&gt;&lt;span class="kwrd"&gt;unit&lt;/span&gt; MailIt;&lt;br /&gt;&lt;br /&gt;&lt;span class="rem"&gt;{requires indy10 - the LATER VERSIONS}&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span class="kwrd"&gt;interface&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span class="kwrd"&gt;uses&lt;/span&gt; Classes, SysUtils, IdSMTP, IdLogFile;&lt;br /&gt;&lt;br /&gt;&lt;span class="kwrd"&gt;type&lt;/span&gt;&lt;br /&gt;  &lt;span class="rem"&gt;//this class encapsulates the "where to" and "what" portions of the message&lt;/span&gt;&lt;br /&gt;  &lt;span class="rem"&gt;//basically, it sends the BODY, including the files in the FILES list, using the SUBJECT to every person on the SendTo, etc. list&lt;/span&gt;&lt;br /&gt;  &lt;span class="rem"&gt;//SendTo, CCSendTo, and BccSendTo all take comma separated addresses (i.e, SendTo:='first@me.com,second@me.com';)&lt;/span&gt;&lt;br /&gt;  TDestinationPart = &lt;span class="kwrd"&gt;class&lt;/span&gt;&lt;br /&gt;                     SendTo    : &lt;span class="kwrd"&gt;string&lt;/span&gt;; &lt;span class="rem"&gt;//list of addresses&lt;/span&gt;&lt;br /&gt;                     CCSendTo  : &lt;span class="kwrd"&gt;string&lt;/span&gt;;&lt;br /&gt;                     BccSendTo : &lt;span class="kwrd"&gt;string&lt;/span&gt;;&lt;br /&gt;                     ReturnAddy: &lt;span class="kwrd"&gt;string&lt;/span&gt;; &lt;span class="rem"&gt;//if this is blank, there will be no return receipt&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;                     Subject   : &lt;span class="kwrd"&gt;string&lt;/span&gt;;&lt;br /&gt;                     Body      : &lt;span class="kwrd"&gt;string&lt;/span&gt;;&lt;br /&gt;                     Files     : TStringList;&lt;br /&gt;&lt;br /&gt;                     &lt;span class="kwrd"&gt;constructor&lt;/span&gt; Create(aSndTo, aCCSndTo, aBCCSndTo, aRtrnRcptAddy, aSubject, aBody:&lt;span class="kwrd"&gt;string&lt;/span&gt;; aFiles:TStringList);&lt;br /&gt;                     &lt;span class="kwrd"&gt;destructor&lt;/span&gt; Free;&lt;br /&gt;                     &lt;span class="kwrd"&gt;end&lt;/span&gt;;&lt;br /&gt;&lt;br /&gt;  &lt;span class="rem"&gt;//this class encapsulates the "how do i get it there" and "who from" portion of the message&lt;/span&gt;&lt;br /&gt;  &lt;span class="rem"&gt;//since this doesn't frequently change, you can use CreateFromFile and SaveToFile to create a template&lt;/span&gt;&lt;br /&gt;  &lt;span class="rem"&gt;//   and save the typing every time you set it up&lt;/span&gt;&lt;br /&gt;  TOriginPart = &lt;span class="kwrd"&gt;class&lt;/span&gt;&lt;br /&gt;                AuthType : TIdSMTPAuthenticationType;&lt;br /&gt;                FromAddy : &lt;span class="kwrd"&gt;string&lt;/span&gt;;&lt;br /&gt;                UserName : &lt;span class="kwrd"&gt;string&lt;/span&gt;;&lt;br /&gt;                Password : &lt;span class="kwrd"&gt;string&lt;/span&gt;;&lt;br /&gt;                Server   : &lt;span class="kwrd"&gt;string&lt;/span&gt;;&lt;br /&gt;                Port     : integer;&lt;br /&gt;                Debug    : boolean;&lt;br /&gt;                &lt;span class="kwrd"&gt;constructor&lt;/span&gt; Create(aAuthType:TIdSMTPAuthenticationType; aFromAddy, aUserName, aPassword, aServer: &lt;span class="kwrd"&gt;string&lt;/span&gt;; aPort:integer);&lt;br /&gt;                &lt;span class="kwrd"&gt;constructor&lt;/span&gt; CreateFromFile(fn:&lt;span class="kwrd"&gt;string&lt;/span&gt;);&lt;br /&gt;                &lt;span class="kwrd"&gt;procedure&lt;/span&gt; SaveToFile(fn:&lt;span class="kwrd"&gt;string&lt;/span&gt;);&lt;br /&gt;                &lt;span class="kwrd"&gt;end&lt;/span&gt;;&lt;br /&gt;&lt;br /&gt;  &lt;span class="rem"&gt;//this is the entire message&lt;/span&gt;&lt;br /&gt;  &lt;span class="rem"&gt;//you provide a DestinationPart and OriginPart and send the file using SendNow.&lt;/span&gt;&lt;br /&gt;  &lt;span class="rem"&gt;//   Check SentOk afterwards to make sure it went.&lt;/span&gt;&lt;br /&gt;  &lt;span class="rem"&gt;//   Any error message will be in SendMsg&lt;/span&gt;&lt;br /&gt;  TMailMessage = &lt;span class="kwrd"&gt;class&lt;/span&gt;&lt;br /&gt;                 &lt;span class="kwrd"&gt;public&lt;/span&gt;&lt;br /&gt;                 Destination : TDestinationPart;&lt;br /&gt;                 Origin      : TOriginPart;&lt;br /&gt;                 SentOk      : boolean;&lt;br /&gt;                 SentMsg     : &lt;span class="kwrd"&gt;string&lt;/span&gt;;&lt;br /&gt;                 logFile     : TIdLogFile;&lt;br /&gt;&lt;br /&gt;                 &lt;span class="kwrd"&gt;constructor&lt;/span&gt; Create(Dest:TDestinationPart; Orig:TOriginPart);&lt;br /&gt;                 &lt;span class="kwrd"&gt;procedure&lt;/span&gt; SendNow;&lt;br /&gt;                 &lt;span class="kwrd"&gt;destructor&lt;/span&gt; Free;&lt;br /&gt;                 &lt;span class="kwrd"&gt;end&lt;/span&gt;;&lt;br /&gt;&lt;br /&gt;  &lt;span class="rem"&gt;//this REPLACES TMailMessage with a Threaded version.&lt;/span&gt;&lt;br /&gt;  &lt;span class="rem"&gt;//You may want to use the FreeOnTerminate flag to create a "Fire and Forget" threaded solution&lt;/span&gt;&lt;br /&gt;  &lt;span class="rem"&gt;//   NOTE: DO NOT GO CRAZY&lt;/span&gt;&lt;br /&gt;  &lt;span class="rem"&gt;//         Pay attention to the documentation of the OS (try this for what I mean http://blogs.msdn.com/oldnewthing/archive/2005/07/29/444912.aspx)&lt;/span&gt;&lt;br /&gt;  &lt;span class="rem"&gt;//         If you've got a really great quad-cpu quad-core rig, you may want to use a bigger number&lt;/span&gt;&lt;br /&gt;  TThreadMailMessage = &lt;span class="kwrd"&gt;class&lt;/span&gt;(TThread)                           &lt;span class="rem"&gt;//you get no error results or other&lt;/span&gt;&lt;br /&gt;                       &lt;span class="kwrd"&gt;protected&lt;/span&gt;                                &lt;span class="rem"&gt;//information from this class, it just tries to send the message in the&lt;/span&gt;&lt;br /&gt;                          MailMsg : TMailMessage;               &lt;span class="rem"&gt;//background.make sure you use the debug function if you're having problems&lt;/span&gt;&lt;br /&gt;                          &lt;span class="kwrd"&gt;procedure&lt;/span&gt; Execute; &lt;span class="kwrd"&gt;override&lt;/span&gt;;&lt;br /&gt;                       &lt;span class="kwrd"&gt;public&lt;/span&gt;&lt;br /&gt;                          &lt;span class="kwrd"&gt;constructor&lt;/span&gt; Create(aDestinationPart:TDestinationPart;&lt;br /&gt;                                             aOriginPart:TOriginPart);&lt;br /&gt;                       &lt;span class="kwrd"&gt;end&lt;/span&gt;;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;span class="rem"&gt;//NOTE: The following utility entries use CriticalSections. DO NOT HAMMER THEM.&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span class="rem"&gt;//You can test this to see if all the TThreadedMailMessages have completed&lt;/span&gt;&lt;br /&gt;&lt;span class="kwrd"&gt;function&lt;/span&gt; MailThreadsDone:boolean;&lt;br /&gt;&lt;span class="rem"&gt;//A count of the number of TThreadedMailMessages are still out there&lt;/span&gt;&lt;br /&gt;&lt;span class="kwrd"&gt;function&lt;/span&gt; ActiveMailThreadCount:integer;&lt;br /&gt;&lt;br /&gt;&lt;span class="kwrd"&gt;implementation&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;uses IdGlobal, IdResourceStringsCore, IdGlobalProtocols, IdResourceStrings, IdExplicitTLSClientServerBase,&lt;br /&gt;    IDPOP3, IdMessage, IdEmailAddress, IdWinSock2, IdIOHandler, IdSSLOpenSSL, IdException,&lt;br /&gt;    IdAttachmentFile, IdText, IdSASL_CRAM_MD5, IdUserPassProvider, IniFiles,&lt;br /&gt;    IdIOHandlerStream, Dialogs, windows;&lt;br /&gt;&lt;br /&gt;&lt;span class="kwrd"&gt;const&lt;/span&gt;&lt;br /&gt;  logFileName=&lt;span class="str"&gt;'mailit.log'&lt;/span&gt;; &lt;span class="rem"&gt;//the default log file name&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span class="kwrd"&gt;var&lt;/span&gt;&lt;br /&gt;  ActiveMailThreads : integer=0;&lt;br /&gt;  MailThreadCSR     : TRTLCriticalSection;&lt;br /&gt;&lt;br /&gt;&lt;span class="rem"&gt;// ---------------------------------------------------------------------------&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span class="kwrd"&gt;type&lt;/span&gt;&lt;br /&gt; &lt;span class="rem"&gt;// this is a descendant &lt;span class="kwrd"&gt;of&lt;/span&gt; TidLogFile, it will create a plain text file &lt;span class="kwrd"&gt;with&lt;/span&gt;&lt;/span&gt;&lt;br /&gt; &lt;span class="rem"&gt;// information about the transfer session&lt;/span&gt;&lt;br /&gt; TlogFile = &lt;span class="kwrd"&gt;class&lt;/span&gt;(TidLogFile)&lt;br /&gt; &lt;span class="kwrd"&gt;protected&lt;/span&gt;&lt;br /&gt;   &lt;span class="kwrd"&gt;procedure&lt;/span&gt; LogReceivedData(&lt;span class="kwrd"&gt;const&lt;/span&gt; AText, AData: &lt;span class="kwrd"&gt;string&lt;/span&gt;); &lt;span class="kwrd"&gt;override&lt;/span&gt;;&lt;br /&gt;   &lt;span class="kwrd"&gt;procedure&lt;/span&gt; LogSentData(&lt;span class="kwrd"&gt;const&lt;/span&gt; AText, AData: &lt;span class="kwrd"&gt;string&lt;/span&gt;); &lt;span class="kwrd"&gt;override&lt;/span&gt;;&lt;br /&gt;   &lt;span class="kwrd"&gt;procedure&lt;/span&gt; LogStatus(&lt;span class="kwrd"&gt;const&lt;/span&gt; AText: &lt;span class="kwrd"&gt;string&lt;/span&gt;); &lt;span class="kwrd"&gt;override&lt;/span&gt;;&lt;br /&gt; &lt;span class="kwrd"&gt;public&lt;/span&gt;&lt;br /&gt;   &lt;span class="kwrd"&gt;procedure&lt;/span&gt; LogWriteString(&lt;span class="kwrd"&gt;const&lt;/span&gt; AText: &lt;span class="kwrd"&gt;string&lt;/span&gt;); &lt;span class="kwrd"&gt;override&lt;/span&gt;;&lt;br /&gt;   &lt;span class="kwrd"&gt;class&lt;/span&gt; &lt;span class="kwrd"&gt;function&lt;/span&gt; buildLogLine(data, prefix: &lt;span class="kwrd"&gt;string&lt;/span&gt;) : &lt;span class="kwrd"&gt;string&lt;/span&gt;;&lt;br /&gt; &lt;span class="kwrd"&gt;end&lt;/span&gt;;&lt;br /&gt;&lt;br /&gt;&lt;span class="rem"&gt;// this ensures the output &lt;span class="kwrd"&gt;of&lt;/span&gt; error and debug logs are in the same format, regardless &lt;span class="kwrd"&gt;of&lt;/span&gt; source&lt;/span&gt;&lt;br /&gt;&lt;span class="kwrd"&gt;class&lt;/span&gt; &lt;span class="kwrd"&gt;function&lt;/span&gt; TlogFile.buildLogLine(data, prefix: &lt;span class="kwrd"&gt;string&lt;/span&gt;) : &lt;span class="kwrd"&gt;string&lt;/span&gt;;&lt;br /&gt;&lt;span class="kwrd"&gt;begin&lt;/span&gt;&lt;br /&gt;&lt;br /&gt; data := StringReplace(data, EOL, RSLogEOL, [rfReplaceAll]);&lt;br /&gt; data := StringReplace(data, CR,  RSLogCR,  [rfReplaceAll]);&lt;br /&gt; data := StringReplace(data, LF,  RSLogLF,  [rfReplaceAll]);&lt;br /&gt;&lt;br /&gt; result := FormatDateTime(&lt;span class="str"&gt;'yy/mm/dd hh:nn:ss'&lt;/span&gt;, now) + &lt;span class="str"&gt;' '&lt;/span&gt;;&lt;br /&gt; &lt;span class="kwrd"&gt;if&lt;/span&gt; (prefix &amp;lt;&amp;gt; &lt;span class="str"&gt;''&lt;/span&gt;) &lt;span class="kwrd"&gt;then&lt;/span&gt;&lt;br /&gt;   result := result + prefix + &lt;span class="str"&gt;' '&lt;/span&gt;;&lt;br /&gt; result := result + data + EOL;&lt;br /&gt;&lt;span class="kwrd"&gt;end&lt;/span&gt;;&lt;br /&gt;&lt;br /&gt;&lt;span class="rem"&gt;// ---------------------------------------------------------------------------&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span class="kwrd"&gt;procedure&lt;/span&gt; TlogFile.LogReceivedData(&lt;span class="kwrd"&gt;const&lt;/span&gt; AText, AData: &lt;span class="kwrd"&gt;string&lt;/span&gt;);&lt;br /&gt;&lt;span class="kwrd"&gt;begin&lt;/span&gt;&lt;br /&gt; &lt;span class="rem"&gt;// ignore AText as it contains the date/time&lt;/span&gt;&lt;br /&gt; LogWriteString(buildLogLine(Adata, &lt;span class="str"&gt;'&amp;lt;&amp;lt;'&lt;/span&gt;));&lt;br /&gt;&lt;span class="kwrd"&gt;end&lt;/span&gt;;&lt;br /&gt;&lt;br /&gt;&lt;span class="rem"&gt;// ---------------------------------------------------------------------------&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span class="kwrd"&gt;procedure&lt;/span&gt; TlogFile.LogSentData(&lt;span class="kwrd"&gt;const&lt;/span&gt; AText, AData: &lt;span class="kwrd"&gt;string&lt;/span&gt;);&lt;br /&gt;&lt;span class="kwrd"&gt;begin&lt;/span&gt;&lt;br /&gt; &lt;span class="rem"&gt;// ignore AText as it contains the date/time&lt;/span&gt;&lt;br /&gt; LogWriteString(buildLogLine(Adata, &lt;span class="str"&gt;'&amp;gt;&amp;gt;'&lt;/span&gt;));&lt;br /&gt;&lt;span class="kwrd"&gt;end&lt;/span&gt;;&lt;br /&gt;&lt;br /&gt;&lt;span class="rem"&gt;// ---------------------------------------------------------------------------&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span class="kwrd"&gt;procedure&lt;/span&gt; TlogFile.LogStatus(&lt;span class="kwrd"&gt;const&lt;/span&gt; AText: &lt;span class="kwrd"&gt;string&lt;/span&gt;);&lt;br /&gt;&lt;span class="kwrd"&gt;begin&lt;/span&gt;&lt;br /&gt; LogWriteString(buildLogLine(AText, &lt;span class="str"&gt;'**'&lt;/span&gt;));&lt;br /&gt;&lt;span class="kwrd"&gt;end&lt;/span&gt;;&lt;br /&gt;&lt;br /&gt;&lt;span class="rem"&gt;// ---------------------------------------------------------------------------&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span class="kwrd"&gt;procedure&lt;/span&gt; TlogFile.LogWriteString(&lt;span class="kwrd"&gt;const&lt;/span&gt; AText: &lt;span class="kwrd"&gt;string&lt;/span&gt;);&lt;br /&gt;&lt;span class="kwrd"&gt;begin&lt;/span&gt;&lt;br /&gt; &lt;span class="rem"&gt;// protected --&amp;gt; public&lt;/span&gt;&lt;br /&gt; inherited;&lt;br /&gt;&lt;span class="kwrd"&gt;end&lt;/span&gt;;&lt;br /&gt;                                                     &lt;br /&gt;&lt;span class="rem"&gt;// ---------------------------------------------------------------------------&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;span class="rem"&gt;// ---------------------------------------------------------------------------&lt;/span&gt;&lt;br /&gt;{TMailMessage}&lt;br /&gt;&lt;span class="rem"&gt;// ---------------------------------------------------------------------------&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span class="kwrd"&gt;constructor&lt;/span&gt; TMailMessage.Create(Dest:TDestinationPart; Orig:TOriginPart);&lt;br /&gt;&lt;span class="kwrd"&gt;begin&lt;/span&gt;&lt;br /&gt;Destination:=Dest;&lt;br /&gt;Origin:=Orig;&lt;br /&gt;&lt;span class="rem"&gt;//the class expects these, it will create them by default&lt;/span&gt;&lt;br /&gt;&lt;span class="kwrd"&gt;if&lt;/span&gt; Destination=nil &lt;span class="kwrd"&gt;then&lt;/span&gt; Destination:=TDestinationPart.Create(&lt;span class="str"&gt;''&lt;/span&gt;,&lt;span class="str"&gt;''&lt;/span&gt;,&lt;span class="str"&gt;''&lt;/span&gt;,&lt;span class="str"&gt;''&lt;/span&gt;,&lt;span class="str"&gt;''&lt;/span&gt;,&lt;span class="str"&gt;''&lt;/span&gt;,TStringList.Create);&lt;br /&gt;&lt;span class="kwrd"&gt;if&lt;/span&gt; Origin=nil      &lt;span class="kwrd"&gt;then&lt;/span&gt; Origin:=TOriginPart.Create(satDefault,&lt;span class="str"&gt;''&lt;/span&gt;,&lt;span class="str"&gt;''&lt;/span&gt;,&lt;span class="str"&gt;''&lt;/span&gt;,&lt;span class="str"&gt;''&lt;/span&gt;,0);&lt;br /&gt;&lt;span class="kwrd"&gt;end&lt;/span&gt;;&lt;br /&gt;&lt;br /&gt;&lt;span class="rem"&gt;// ---------------------------------------------------------------------------&lt;/span&gt;&lt;br /&gt;&lt;span class="kwrd"&gt;procedure&lt;/span&gt; TMailMessage.SendNow;&lt;br /&gt;&lt;span class="kwrd"&gt;var&lt;/span&gt; MsgSend:TIdMessage;&lt;br /&gt;   SMTP:TIdSMTP;&lt;br /&gt;   ix:integer;&lt;br /&gt;   SASLLogin:TIdSASLCramMD5;&lt;br /&gt;   UserPassProv:TIdUserPassProvider;&lt;br /&gt;   textPart:TIdText;&lt;br /&gt;&lt;span class="kwrd"&gt;begin&lt;/span&gt;&lt;br /&gt;  logFile := nil;                                                     &lt;span class="rem"&gt;//init to no logging&lt;/span&gt;&lt;br /&gt;  MsgSend:=TIdMessage.Create;                                         &lt;span class="rem"&gt;//create the message&lt;/span&gt;&lt;br /&gt;  &lt;span class="kwrd"&gt;with&lt;/span&gt; MsgSend &lt;span class="kwrd"&gt;&lt;span class="kwrd"&gt;do&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;     &lt;span class="kwrd"&gt;begin&lt;/span&gt;&lt;br /&gt;        Body.Text:=Destination.Body;&lt;br /&gt;        &lt;span class="kwrd"&gt;if&lt;/span&gt; POS(&lt;span class="str"&gt;'&amp;lt;html&amp;gt;'&lt;/span&gt;,Body.Text)&amp;lt;&amp;gt;0 &lt;span class="kwrd"&gt;then&lt;/span&gt;&lt;br /&gt;           &lt;span class="kwrd"&gt;if&lt;/span&gt; (Destination.Files&amp;lt;&amp;gt;nil) AND (Destination.Files.Count&amp;gt;0) &lt;span class="kwrd"&gt;then&lt;/span&gt; &lt;span class="rem"&gt;//if you are using attachments &lt;span class="kwrd"&gt;with&lt;/span&gt; html mail, you have &lt;span class="kwrd"&gt;do&lt;/span&gt; &lt;span class="kwrd"&gt;do&lt;/span&gt; it in sections&lt;/span&gt;&lt;br /&gt;              &lt;span class="kwrd"&gt;begin&lt;/span&gt;&lt;br /&gt;              Body.Text:=&lt;span class="str"&gt;''&lt;/span&gt;;                                          &lt;span class="rem"&gt;//clear the body&lt;/span&gt;&lt;br /&gt;              contentType:=&lt;span class="str"&gt;'multipart/alternative'&lt;/span&gt;;                   &lt;span class="rem"&gt;//setup the message parts&lt;/span&gt;&lt;br /&gt;              textPart:=TIdText.Create(MsgSend.MessageParts,nil);     &lt;span class="rem"&gt;// this is for plain text&lt;/span&gt;&lt;br /&gt;              textPart.ContentType:=&lt;span class="str"&gt;'text/plain'&lt;/span&gt;;                     &lt;span class="rem"&gt;// set the content &lt;span class="kwrd"&gt;type&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;              textPart.Body.Add(&lt;span class="str"&gt;'This message is formatted as HTML.'&lt;/span&gt;);&lt;span class="rem"&gt;// just tell the user that the message is html - it would be nice to strip the html, but you'd never make it look right. probably should add support for a plain text and html text in the Destination class&lt;/span&gt;&lt;br /&gt;              textPart.Body.Add(Destination.Body);                    &lt;span class="rem"&gt;// add the plain text part which is really html formatted&lt;/span&gt;&lt;br /&gt;              textPart:=TIdText.Create(MsgSend.MessageParts,nil);     &lt;span class="rem"&gt;// this is for html text (which is basically just plain text &lt;span class="kwrd"&gt;with&lt;/span&gt; special rules)&lt;/span&gt;&lt;br /&gt;              textPart.ContentType:=&lt;span class="str"&gt;'text/html'&lt;/span&gt;;                      &lt;span class="rem"&gt;// set the content &lt;span class="kwrd"&gt;type&lt;/span&gt; - this is the magic that kicks in the special rules&lt;/span&gt;&lt;br /&gt;              textPart.Body.Add(Destination.Body);                    &lt;span class="rem"&gt;// add the html formatted text&lt;/span&gt;&lt;br /&gt;              &lt;span class="kwrd"&gt;end&lt;/span&gt;&lt;br /&gt;           &lt;span class="kwrd"&gt;else&lt;/span&gt;&lt;br /&gt;              contentType:=&lt;span class="str"&gt;'text/html'&lt;/span&gt;;                               &lt;span class="rem"&gt;//you can just send it as an html message&lt;/span&gt;&lt;br /&gt;        From.Text := Origin.FromAddy;                                 &lt;span class="rem"&gt;//setup the from address&lt;/span&gt;&lt;br /&gt;        Recipients.EMailAddresses := Destination.SendTo;              &lt;span class="rem"&gt;//setup who it's going to&lt;/span&gt;&lt;br /&gt;        Subject := Destination.Subject;                               &lt;span class="rem"&gt;//set the subject&lt;/span&gt;&lt;br /&gt;        Priority := mpNormal;                                         &lt;span class="rem"&gt;//set the priority (note that you could add to Destination to support different priorities)&lt;/span&gt;&lt;br /&gt;        CCList.EMailAddresses := Destination.CCSendTo;                &lt;span class="rem"&gt;//set the CC list&lt;/span&gt;&lt;br /&gt;        BccList.EMailAddresses := Destination.BCCSendTo;              &lt;span class="rem"&gt;//set the BCC list&lt;/span&gt;&lt;br /&gt;        ReceiptRecipient.Text := Destination.ReturnAddy;              &lt;span class="rem"&gt;//set the return receipt address&lt;/span&gt;&lt;br /&gt;     &lt;span class="kwrd"&gt;end&lt;/span&gt;;&lt;br /&gt;&lt;br /&gt;  &lt;span class="kwrd"&gt;for&lt;/span&gt; ix:=0 to Destination.Files.Count-1 &lt;span class="kwrd"&gt;&lt;span class="kwrd"&gt;do&lt;/span&gt;&lt;/span&gt;                            &lt;span class="rem"&gt;//if we got a list &lt;span class="kwrd"&gt;of&lt;/span&gt; file names, add each file as an attachment&lt;/span&gt;&lt;br /&gt;     TIdAttachmentFile.Create(MsgSend.MessageParts, Destination.Files.Strings[ix]);&lt;br /&gt;&lt;br /&gt;  &lt;span class="kwrd"&gt;try&lt;/span&gt;&lt;br /&gt;    SMTP:=TIdSMTP.Create;                                              &lt;span class="rem"&gt;//create the SMTP object&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;    &lt;span class="kwrd"&gt;try&lt;/span&gt;&lt;br /&gt;      TIdSSLContext.Create.Free;                                       &lt;span class="rem"&gt;//try to create a SSL context (immediately disposes &lt;span class="kwrd"&gt;of&lt;/span&gt; it) - need OpenSSL to support this, if it fails, it will fall into the exception&lt;/span&gt;&lt;br /&gt;      smtp.IOHandler := TIdSSLIOHandlerSocketOpenSSL.Create(smtp);     &lt;span class="rem"&gt;//if we succeed, &lt;span class="kwrd"&gt;then&lt;/span&gt; we can create a SSL socket handler and assign it to the IOHandler&lt;/span&gt;&lt;br /&gt;      smtp.UseTLS := utUseExplicitTLS;                                 &lt;span class="rem"&gt;//and we can mark the we can use tls&lt;/span&gt;&lt;br /&gt;    except&lt;br /&gt;      smtp.IOHandler := TIdIOHandler.MakeDefaultIOHandler(smtp);       &lt;span class="rem"&gt;//the SSL failed to create, so make the default IO handler&lt;/span&gt;&lt;br /&gt;      smtp.UseTLS := utNoTLSSupport;                                   &lt;span class="rem"&gt;//mark that we have no TLS support&lt;/span&gt;&lt;br /&gt;    &lt;span class="kwrd"&gt;end&lt;/span&gt;;&lt;br /&gt;    smtp.ManagedIOHandler := True;                                     &lt;span class="rem"&gt;//either way, we now have a ManagedIOHandler&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;    &lt;span class="kwrd"&gt;if&lt;/span&gt; Origin.Debug &lt;span class="kwrd"&gt;then&lt;/span&gt;                                               &lt;span class="rem"&gt;//if we marked that we wanted debugging, we need to &lt;span class="kwrd"&gt;do&lt;/span&gt; some setup&lt;/span&gt;&lt;br /&gt;       &lt;span class="kwrd"&gt;begin&lt;/span&gt;&lt;br /&gt;       logFile := TLogFile.Create(nil);                                &lt;span class="rem"&gt;//create the log file&lt;/span&gt;&lt;br /&gt;       logFile.FileName:=logFileName;                                  &lt;span class="rem"&gt;//set the default log file name - NOTE: you could get fancy &lt;span class="kwrd"&gt;with&lt;/span&gt; this, but I normally don't use it&lt;/span&gt;&lt;br /&gt;       logFile.Active:=&lt;span class="kwrd"&gt;true&lt;/span&gt;;                                           &lt;span class="rem"&gt;//activate the log file (creates the file and intializes everything)&lt;/span&gt;&lt;br /&gt;       smtp.IOHandler.Intercept := logFile;                            &lt;span class="rem"&gt;//set the logFile to the intercept &lt;span class="kwrd"&gt;of&lt;/span&gt; the IOHandler to capture the events&lt;/span&gt;&lt;br /&gt;       smtp.IOHandler.OnStatus  := smtp.OnStatus;                      &lt;span class="rem"&gt;// - not sure why we &lt;span class="kwrd"&gt;do&lt;/span&gt; this, copied code -&lt;/span&gt;&lt;br /&gt;       &lt;span class="kwrd"&gt;end&lt;/span&gt;;&lt;br /&gt;&lt;br /&gt;    &lt;span class="kwrd"&gt;try&lt;/span&gt;&lt;br /&gt;      SMTP.AuthType := Origin.AuthType;                                &lt;span class="rem"&gt;//setup the auth &lt;span class="kwrd"&gt;type&lt;/span&gt; : satNONE, satDEFAULT, satSASL&lt;/span&gt;&lt;br /&gt;      SMTP.UserName := Origin.UserName;                                &lt;span class="rem"&gt;//setup the user name&lt;/span&gt;&lt;br /&gt;      SMTP.Password := Origin.Password;                                &lt;span class="rem"&gt;//setup the password&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;      userPassProv:=TIdUserPassProvider.Create;                        &lt;span class="rem"&gt;//create the user/pass provider - this handles the login functions for SASL&lt;/span&gt;&lt;br /&gt;      userPassProv.UserName:=SMTP.UserName;                            &lt;span class="rem"&gt;// setup user name&lt;/span&gt;&lt;br /&gt;      userPassProv.Password:=SMTP.Password;                            &lt;span class="rem"&gt;// &amp;amp; password&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;      &lt;span class="kwrd"&gt;if&lt;/span&gt; SMTP.AuthType=satSASL &lt;span class="kwrd"&gt;then&lt;/span&gt;                                    &lt;span class="rem"&gt;//if we are going to use SASL - basically, SASL just encrypts the login, everything else is still clear text&lt;/span&gt;&lt;br /&gt;        &lt;span class="kwrd"&gt;begin&lt;/span&gt;&lt;br /&gt;        SASLLogin:=TIdSASLCramMd5.Create;                              &lt;span class="rem"&gt;// create the CramMd5 provider - see http://en.wikipedia.org/wiki/CRAM-MD5 - this is the encryptor&lt;/span&gt;&lt;br /&gt;        SASLLogin.UserPassProvider:=userPassProv;                      &lt;span class="rem"&gt;// assign the user pass provider to it&lt;/span&gt;&lt;br /&gt;        SMTP.SASLMechanisms.Add.SASL:=SASLLogin;                       &lt;span class="rem"&gt;// add the SASL login back to the SMTP object&lt;/span&gt;&lt;br /&gt;        &lt;span class="kwrd"&gt;end&lt;/span&gt;;&lt;br /&gt;&lt;br /&gt;      {General setup}&lt;br /&gt;      SMTP.Host := Origin.Server;                                      &lt;span class="rem"&gt;//setup the server name&lt;/span&gt;&lt;br /&gt;      SMTP.Port := Origin.Port;                                        &lt;span class="rem"&gt;//setup the server port&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;      {now we send the message}&lt;br /&gt;      SMTP.Connect;                                                    &lt;span class="rem"&gt;//connect to the server - this will automatically use TLS if configured and supported&lt;/span&gt;&lt;br /&gt;      &lt;span class="kwrd"&gt;if&lt;/span&gt; not SMTP.Authenticate &lt;span class="kwrd"&gt;then&lt;/span&gt;                                    &lt;span class="rem"&gt;//authenticate &lt;span class="kwrd"&gt;with&lt;/span&gt; the server - this will automatically use SASL if configured and supported&lt;/span&gt;&lt;br /&gt;         &lt;span class="kwrd"&gt;begin&lt;/span&gt;&lt;br /&gt;         MessageDlg(&lt;span class="str"&gt;'An error occurred attempting to send your e-mail. The error was : Unable to authenticate.'&lt;/span&gt;, mtError, [mbOK], 0);&lt;br /&gt;         exit;&lt;br /&gt;         &lt;span class="kwrd"&gt;end&lt;/span&gt;;&lt;br /&gt;      &lt;span class="kwrd"&gt;try&lt;/span&gt;&lt;br /&gt;         &lt;span class="kwrd"&gt;try&lt;/span&gt;&lt;br /&gt;            SMTP.Send(MsgSend);                                        &lt;span class="rem"&gt;//send the message&lt;/span&gt;&lt;br /&gt;            SentOk:=&lt;span class="kwrd"&gt;true&lt;/span&gt;;                                              &lt;span class="rem"&gt;//indicate success&lt;/span&gt;&lt;br /&gt;         &lt;span class="kwrd"&gt;finally&lt;/span&gt;&lt;br /&gt;            SMTP.Disconnect;                                           &lt;span class="rem"&gt;//disconnect from the server&lt;/span&gt;&lt;br /&gt;         &lt;span class="kwrd"&gt;end&lt;/span&gt;;&lt;br /&gt;      except on E :Exception &lt;span class="kwrd"&gt;&lt;span class="kwrd"&gt;do&lt;/span&gt;&lt;/span&gt;                                        &lt;span class="rem"&gt;//if we had a failure, say so&lt;/span&gt;&lt;br /&gt;         &lt;span class="kwrd"&gt;begin&lt;/span&gt;&lt;br /&gt;         MessageDlg(&lt;span class="str"&gt;'An error occurred attempting to send your e-mail. The error was : '&lt;/span&gt;+E.Message, mtError, [mbOK], 0);&lt;br /&gt;         SentOk:=&lt;span class="kwrd"&gt;false&lt;/span&gt;;                                                &lt;span class="rem"&gt;//set failure&lt;/span&gt;&lt;br /&gt;         SentMsg:=E.Message;                                           &lt;span class="rem"&gt;//and grab the error message&lt;/span&gt;&lt;br /&gt;         &lt;span class="kwrd"&gt;end&lt;/span&gt;;&lt;br /&gt;      &lt;span class="kwrd"&gt;end&lt;/span&gt;;&lt;br /&gt;    &lt;span class="kwrd"&gt;finally&lt;/span&gt;&lt;br /&gt;    SMTP.Free;                                                         &lt;span class="rem"&gt;//free the memory&lt;/span&gt;&lt;br /&gt;    &lt;span class="kwrd"&gt;end&lt;/span&gt;;&lt;br /&gt;  &lt;span class="kwrd"&gt;finally&lt;/span&gt;&lt;br /&gt;     &lt;span class="kwrd"&gt;if&lt;/span&gt; logFile&amp;lt;&amp;gt;nil &lt;span class="kwrd"&gt;then&lt;/span&gt;                                              &lt;span class="rem"&gt;//if we had a log file, free that&lt;/span&gt;&lt;br /&gt;        logFile.Free;&lt;br /&gt;     MsgSend.Free;                                                     &lt;span class="rem"&gt;//free the message&lt;/span&gt;&lt;br /&gt;  &lt;span class="kwrd"&gt;end&lt;/span&gt;;&lt;br /&gt;&lt;span class="kwrd"&gt;end&lt;/span&gt;;&lt;br /&gt;&lt;br /&gt;&lt;span class="rem"&gt;// ---------------------------------------------------------------------------&lt;/span&gt;&lt;br /&gt;destructor TMailMessage.Free;&lt;br /&gt;&lt;span class="kwrd"&gt;begin&lt;/span&gt;&lt;br /&gt;Destination.Free;                                                      &lt;span class="rem"&gt;//free the destination&lt;/span&gt;&lt;br /&gt;Origin.Free;                                                           &lt;span class="rem"&gt;//free the origin&lt;/span&gt;&lt;br /&gt;&lt;span class="kwrd"&gt;end&lt;/span&gt;;&lt;br /&gt;&lt;br /&gt;&lt;span class="rem"&gt;// ---------------------------------------------------------------------------&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;span class="rem"&gt;// ---------------------------------------------------------------------------&lt;/span&gt;&lt;br /&gt;{TDestinationPart}&lt;br /&gt;&lt;span class="rem"&gt;// ---------------------------------------------------------------------------&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span class="kwrd"&gt;constructor&lt;/span&gt; TDestinationPart.Create(aSndTo, aCCSndTo, aBCCSndTo, aRtrnRcptAddy, aSubject, aBody:&lt;span class="kwrd"&gt;string&lt;/span&gt;; aFiles:TStringList);&lt;br /&gt;&lt;span class="kwrd"&gt;begin&lt;/span&gt;&lt;br /&gt;SendTo    := aSndTo;          &lt;span class="rem"&gt;//send message to, comma separate list for multiple adddesses&lt;/span&gt;&lt;br /&gt;CCSendTo  := aCCSndTo;        &lt;span class="rem"&gt;//CC message to&lt;/span&gt;&lt;br /&gt;BccSendTo := aBCCSndTo;       &lt;span class="rem"&gt;//BCC message to&lt;/span&gt;&lt;br /&gt;ReturnAddy:= aRtrnRcptAddy;   &lt;span class="rem"&gt;//leave blank for not return receipt. set if you want a return receipt (me@mydomain.com)&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;Subject   := aSubject;        &lt;span class="rem"&gt;//what's it about&lt;/span&gt;&lt;br /&gt;Body      := aBody;           &lt;span class="rem"&gt;//the text, supports HTML or TEXT&lt;/span&gt;&lt;br /&gt;Files     := aFiles;          &lt;span class="rem"&gt;//a list &lt;span class="kwrd"&gt;of&lt;/span&gt; files to upload - WATCH THIS - you are giving up control by passing in the list, this list is free'd in the destructor&lt;/span&gt;&lt;br /&gt;&lt;span class="kwrd"&gt;if&lt;/span&gt; Files=nil &lt;span class="kwrd"&gt;then&lt;/span&gt;&lt;br /&gt;  Files:=TStringList.Create; &lt;span class="rem"&gt;//we must have a list, create if not provided&lt;/span&gt;&lt;br /&gt;&lt;span class="kwrd"&gt;end&lt;/span&gt;;&lt;br /&gt;&lt;br /&gt;&lt;span class="rem"&gt;// ---------------------------------------------------------------------------&lt;/span&gt;&lt;br /&gt;destructor TDestinationPart.Free;&lt;br /&gt;&lt;span class="kwrd"&gt;begin&lt;/span&gt;&lt;br /&gt;Files.Free;                   &lt;span class="rem"&gt;//free space claimed in create - watch this, it takes control &lt;span class="kwrd"&gt;of&lt;/span&gt; the list passed in the create and will dispose &lt;span class="kwrd"&gt;of&lt;/span&gt; it, can cause A/Vs&lt;/span&gt;&lt;br /&gt;&lt;span class="kwrd"&gt;end&lt;/span&gt;;&lt;br /&gt;&lt;br /&gt;&lt;span class="rem"&gt;// ---------------------------------------------------------------------------&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span class="rem"&gt;// ---------------------------------------------------------------------------&lt;/span&gt;&lt;br /&gt;{TOriginPart}&lt;br /&gt;&lt;span class="rem"&gt;// ---------------------------------------------------------------------------&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span class="kwrd"&gt;constructor&lt;/span&gt; TOriginPart.Create(aAuthType:TIdSMTPAuthenticationType; aFromAddy, aUserName, aPassword, aServer: &lt;span class="kwrd"&gt;string&lt;/span&gt;; aPort:integer);&lt;br /&gt;&lt;span class="kwrd"&gt;begin&lt;/span&gt;&lt;br /&gt;AuthType := aAuthType;    &lt;span class="rem"&gt;//options are : 0=satNONE, 1=satDEFAULT, 2=satSASL&lt;/span&gt;&lt;br /&gt;FromAddy := aFromAddy;    &lt;span class="rem"&gt;//me@mydomain.com&lt;/span&gt;&lt;br /&gt;UserName := aUserName;    &lt;span class="rem"&gt;//me&lt;/span&gt;&lt;br /&gt;Password := aPassword;    &lt;span class="rem"&gt;//mypassword&lt;/span&gt;&lt;br /&gt;Server   := aServer;      &lt;span class="rem"&gt;//smtp.mydomain.com&lt;/span&gt;&lt;br /&gt;Port     := aPort;        &lt;span class="rem"&gt;//SMTP connection port (25 is default)&lt;/span&gt;&lt;br /&gt;Debug    := &lt;span class="kwrd"&gt;false&lt;/span&gt;;        &lt;span class="rem"&gt;//debugging off/on&lt;/span&gt;&lt;br /&gt;&lt;span class="kwrd"&gt;end&lt;/span&gt;;&lt;br /&gt;&lt;br /&gt;&lt;span class="rem"&gt;// ---------------------------------------------------------------------------&lt;/span&gt;&lt;br /&gt;&lt;span class="kwrd"&gt;constructor&lt;/span&gt; TOriginPart.CreateFromFile(fn:&lt;span class="kwrd"&gt;string&lt;/span&gt;);&lt;br /&gt;&lt;span class="kwrd"&gt;var&lt;/span&gt; INF:TIniFile;&lt;br /&gt;   i:integer;&lt;br /&gt;&lt;span class="kwrd"&gt;begin&lt;/span&gt;&lt;br /&gt;INF:=TIniFile.Create(fn);&lt;br /&gt;i        := INF.ReadInteger(&lt;span class="str"&gt;'SMTP'&lt;/span&gt;,&lt;span class="str"&gt;'AuthType'&lt;/span&gt;,ord(satDefault));&lt;br /&gt;&lt;span class="kwrd"&gt;case&lt;/span&gt; i &lt;span class="kwrd"&gt;of&lt;/span&gt;&lt;br /&gt;0 : AuthType := satNONE;&lt;br /&gt;1 : AuthType := satDEFAULT;&lt;br /&gt;2 : AuthType := satSASL;&lt;br /&gt;&lt;span class="kwrd"&gt;end&lt;/span&gt;;&lt;br /&gt;FromAddy := INF.ReadString (&lt;span class="str"&gt;'SMTP'&lt;/span&gt;, &lt;span class="str"&gt;'FromAddy'&lt;/span&gt;, &lt;span class="str"&gt;''&lt;/span&gt;); &lt;span class="rem"&gt;//me@mydomain.com&lt;/span&gt;&lt;br /&gt;UserName := INF.ReadString (&lt;span class="str"&gt;'SMTP'&lt;/span&gt;, &lt;span class="str"&gt;'UserName'&lt;/span&gt;, &lt;span class="str"&gt;''&lt;/span&gt;); &lt;span class="rem"&gt;//me&lt;/span&gt;&lt;br /&gt;Password := INF.ReadString (&lt;span class="str"&gt;'SMTP'&lt;/span&gt;, &lt;span class="str"&gt;'Password'&lt;/span&gt;, &lt;span class="str"&gt;''&lt;/span&gt;); &lt;span class="rem"&gt;//mypassword&lt;/span&gt;&lt;br /&gt;Server   := INF.ReadString (&lt;span class="str"&gt;'SMTP'&lt;/span&gt;, &lt;span class="str"&gt;'Server'&lt;/span&gt;, &lt;span class="str"&gt;''&lt;/span&gt;);   &lt;span class="rem"&gt;//smtp.mydomain.com&lt;/span&gt;&lt;br /&gt;Port     := INF.ReadInteger(&lt;span class="str"&gt;'SMTP'&lt;/span&gt;, &lt;span class="str"&gt;'Port'&lt;/span&gt;, 25);     &lt;span class="rem"&gt;//default SMTP is 25&lt;/span&gt;&lt;br /&gt;Debug    := INF.ReadBool   (&lt;span class="str"&gt;'SMTP'&lt;/span&gt;, &lt;span class="str"&gt;'Debug'&lt;/span&gt;, &lt;span class="kwrd"&gt;false&lt;/span&gt;); &lt;span class="rem"&gt;//we don't we debugging on&lt;/span&gt;&lt;br /&gt;INF.Free;&lt;br /&gt;&lt;span class="kwrd"&gt;end&lt;/span&gt;;&lt;br /&gt;&lt;br /&gt;&lt;span class="rem"&gt;// ---------------------------------------------------------------------------&lt;/span&gt;&lt;br /&gt;&lt;span class="kwrd"&gt;procedure&lt;/span&gt; TOriginPart.SaveToFile(fn:&lt;span class="kwrd"&gt;string&lt;/span&gt;);&lt;br /&gt;&lt;span class="kwrd"&gt;var&lt;/span&gt; INF:TIniFile;&lt;br /&gt;&lt;span class="kwrd"&gt;begin&lt;/span&gt;&lt;br /&gt;INF:=TIniFile.Create(fn);&lt;br /&gt;INF.WriteInteger(&lt;span class="str"&gt;'SMTP'&lt;/span&gt;, &lt;span class="str"&gt;'AuthType'&lt;/span&gt;, ord(AuthType)); &lt;span class="rem"&gt;//options are : 0=satNONE, 1=satDEFAULT, 2=satSASL&lt;/span&gt;&lt;br /&gt;INF.WriteString (&lt;span class="str"&gt;'SMTP'&lt;/span&gt;, &lt;span class="str"&gt;'FromAddy'&lt;/span&gt;, FromAddy);      &lt;span class="rem"&gt;//me@mydomain.com&lt;/span&gt;&lt;br /&gt;INF.WriteString (&lt;span class="str"&gt;'SMTP'&lt;/span&gt;, &lt;span class="str"&gt;'UserName'&lt;/span&gt;, UserName);      &lt;span class="rem"&gt;//me&lt;/span&gt;&lt;br /&gt;INF.WriteString (&lt;span class="str"&gt;'SMTP'&lt;/span&gt;, &lt;span class="str"&gt;'Password'&lt;/span&gt;, Password);      &lt;span class="rem"&gt;//mypassword&lt;/span&gt;&lt;br /&gt;INF.WriteString (&lt;span class="str"&gt;'SMTP'&lt;/span&gt;, &lt;span class="str"&gt;'Server'&lt;/span&gt;,   Server);        &lt;span class="rem"&gt;//smtp.mydomain.com&lt;/span&gt;&lt;br /&gt;INF.WriteInteger(&lt;span class="str"&gt;'SMTP'&lt;/span&gt;, &lt;span class="str"&gt;'Port'&lt;/span&gt;,     Port);          &lt;span class="rem"&gt;//SMTP connection port&lt;/span&gt;&lt;br /&gt;INF.WriteBool   (&lt;span class="str"&gt;'SMTP'&lt;/span&gt;, &lt;span class="str"&gt;'Debug'&lt;/span&gt;,    Debug);         &lt;span class="rem"&gt;//debugging off/on&lt;/span&gt;&lt;br /&gt;INF.Free;&lt;br /&gt;&lt;span class="kwrd"&gt;end&lt;/span&gt;;&lt;br /&gt;&lt;br /&gt;&lt;span class="rem"&gt;// ---------------------------------------------------------------------------&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;span class="rem"&gt;// ---------------------------------------------------------------------------&lt;/span&gt;&lt;br /&gt;{ TThreadMailMessage &amp;amp; util functions &lt;span class="kwrd"&gt;for&lt;/span&gt; it}&lt;br /&gt;&lt;span class="rem"&gt;// ---------------------------------------------------------------------------&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span class="kwrd"&gt;procedure&lt;/span&gt; IncMailThreadCount;&lt;br /&gt;&lt;span class="kwrd"&gt;begin&lt;/span&gt;&lt;br /&gt;  EnterCriticalSection(MailThreadCSR);&lt;br /&gt;  inc(ActiveMailThreads);&lt;br /&gt;  LeaveCriticalSection(MailThreadCSR);&lt;br /&gt;&lt;span class="kwrd"&gt;end&lt;/span&gt;;&lt;br /&gt;&lt;br /&gt;&lt;span class="kwrd"&gt;procedure&lt;/span&gt; DecMailThreadCount;&lt;br /&gt;&lt;span class="kwrd"&gt;begin&lt;/span&gt;&lt;br /&gt;  EnterCriticalSection(MailThreadCSR);&lt;br /&gt;  dec(ActiveMailThreads);&lt;br /&gt;  LeaveCriticalSection(MailThreadCSR);&lt;br /&gt;&lt;span class="kwrd"&gt;end&lt;/span&gt;;&lt;br /&gt;&lt;br /&gt;&lt;span class="kwrd"&gt;function&lt;/span&gt; MailThreadsDone:boolean;&lt;br /&gt;&lt;span class="kwrd"&gt;begin&lt;/span&gt;&lt;br /&gt;  result:=ActiveMailThreadCount=0;&lt;br /&gt;&lt;span class="kwrd"&gt;end&lt;/span&gt;;&lt;br /&gt;&lt;br /&gt;&lt;span class="kwrd"&gt;function&lt;/span&gt; ActiveMailThreadCount:integer;&lt;br /&gt;&lt;span class="kwrd"&gt;begin&lt;/span&gt;&lt;br /&gt;  EnterCriticalSection(MailThreadCSR);&lt;br /&gt;  result:=ActiveMailThreads;&lt;br /&gt;  LeaveCriticalSection(MailThreadCSR);&lt;br /&gt;&lt;span class="kwrd"&gt;end&lt;/span&gt;;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;span class="kwrd"&gt;constructor&lt;/span&gt; TThreadMailMessage.Create(aDestinationPart: TDestinationPart;&lt;br /&gt; aOriginPart: TOriginPart);&lt;br /&gt;&lt;span class="kwrd"&gt;begin&lt;/span&gt;&lt;br /&gt;inherited Create(&lt;span class="kwrd"&gt;false&lt;/span&gt;);&lt;br /&gt;IncMailThreadCount;&lt;br /&gt;&lt;span class="kwrd"&gt;if&lt;/span&gt; aDestinationPart=nil &lt;span class="kwrd"&gt;then&lt;/span&gt; raise Exception.Create(&lt;span class="str"&gt;'You must supply a destination'&lt;/span&gt;);&lt;br /&gt;&lt;span class="kwrd"&gt;if&lt;/span&gt; aOriginPart=nil      &lt;span class="kwrd"&gt;then&lt;/span&gt; raise Exception.Create(&lt;span class="str"&gt;'You must supply an origin'&lt;/span&gt;);&lt;br /&gt;FreeOnTerminate:=&lt;span class="kwrd"&gt;true&lt;/span&gt;;&lt;br /&gt;&lt;br /&gt;MailMsg:=TMailMessage.Create(aDestinationPart, aOriginPart);&lt;br /&gt;&lt;span class="kwrd"&gt;end&lt;/span&gt;;&lt;br /&gt;&lt;br /&gt;&lt;span class="kwrd"&gt;procedure&lt;/span&gt; TThreadMailMessage.Execute;&lt;br /&gt;&lt;span class="kwrd"&gt;begin&lt;/span&gt;&lt;br /&gt;  &lt;span class="kwrd"&gt;try&lt;/span&gt;&lt;br /&gt;     MailMsg.SendNow;&lt;br /&gt;  &lt;span class="kwrd"&gt;finally&lt;/span&gt;&lt;br /&gt;     DecMailThreadCount;&lt;br /&gt;  &lt;span class="kwrd"&gt;end&lt;/span&gt;;&lt;br /&gt;&lt;span class="kwrd"&gt;end&lt;/span&gt;;&lt;br /&gt;&lt;br /&gt;&lt;span class="kwrd"&gt;initialization&lt;/span&gt;&lt;br /&gt;  InitializeCriticalSection(MailThreadCSR);&lt;br /&gt;&lt;br /&gt;&lt;span class="kwrd"&gt;finalization&lt;/span&gt;&lt;br /&gt;  DeleteCriticalSection(MailThreadCSR);&lt;br /&gt;&lt;br /&gt;&lt;span class="kwrd"&gt;end&lt;/span&gt;.&lt;br /&gt;&lt;/pre&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/6458454884392032777-7214315275639670210?l=ruminatedrumblings.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://ruminatedrumblings.blogspot.com/feeds/7214315275639670210/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=6458454884392032777&amp;postID=7214315275639670210' title='13 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/6458454884392032777/posts/default/7214315275639670210'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/6458454884392032777/posts/default/7214315275639670210'/><link rel='alternate' type='text/html' href='http://ruminatedrumblings.blogspot.com/2008/04/smtp-mail-and-indy-again.html' title='SMTP Mail and Indy (again)'/><author><name>Marshall Fryman</name><uri>http://www.blogger.com/profile/02996248168525053524</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>13</thr:total></entry><entry><id>tag:blogger.com,1999:blog-6458454884392032777.post-3620983740808815786</id><published>2008-03-31T15:49:00.000-07:00</published><updated>2008-04-14T13:57:58.184-07:00</updated><title type='text'>Holidays</title><content type='html'>Anyone else out there ever run into the need for a simple little list of holidays? I do a fair amount of stuff that involves questions like "Are we off on such and such a day?" where you have to figure out, "When is Easter this year anyway?" That's pretty easy if you look it up on a calendar. Now try doing that in code.&lt;br /&gt;&lt;br /&gt;At any rate, I wrote a tiny little class to provide some basic holidays out. Help yourself to the code, it's not complicated, just annoying. The biggest trick is &lt;span style="font-weight:bold;"&gt;finding&lt;/span&gt; the information in the first place. This is US-oriented, but I'd be glad to extended it if someone wants some other days in there. It would be helpful if you could provide the holiday information you're interested in though (i.e., My Personal Holiday is the 3rd Tuesday of May or whatever). Oh, one last caveat. If the date doesn't appear (like Inauguration day), the DateTime will be a 0. That's fine for comparisons, but if you just do a dump of the dates, it gives you 1899.&lt;br /&gt;&lt;br /&gt;&lt;!-- code formatted by http://manoli.net/csharpformat/ --&gt;&lt;br /&gt;&lt;pre class="csharpcode"&gt;&lt;br /&gt;&lt;span class="kwrd"&gt;unit&lt;/span&gt; holidayDateTime;&lt;br /&gt;&lt;br /&gt;&lt;span class="kwrd"&gt;interface&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span class="kwrd"&gt;uses&lt;/span&gt; sysutils;&lt;br /&gt;&lt;br /&gt;&lt;span class="kwrd"&gt;type&lt;/span&gt;&lt;br /&gt;   THolidayClass = &lt;span class="kwrd"&gt;class&lt;/span&gt;&lt;br /&gt;     &lt;span class="kwrd"&gt;public&lt;/span&gt;&lt;br /&gt;        YearIs       : &lt;span class="kwrd"&gt;word&lt;/span&gt;;&lt;br /&gt;        NewYears     : TDateTime;&lt;br /&gt;        MLKJr        : TDateTime;&lt;br /&gt;        Inauguration : TDateTime;&lt;br /&gt;        Washington   : TDateTime;&lt;br /&gt;        ArmedForces  : TDateTime;&lt;br /&gt;        Memorial     : TDateTime;&lt;br /&gt;        FlagDay      : TDateTime;&lt;br /&gt;        Independence : TDateTime;&lt;br /&gt;        Labor        : TDateTime;&lt;br /&gt;        Columbus     : TDateTime;&lt;br /&gt;        Veterans     : TDateTime;&lt;br /&gt;        Thanksgiving : TDateTime;&lt;br /&gt;        Christmas    : TDateTime;&lt;br /&gt;        Secretaries  : TDateTime;&lt;br /&gt;        AprilFools   : TDateTime;&lt;br /&gt;        Earth        : TDateTime;&lt;br /&gt;        Fathers      : TDateTime;&lt;br /&gt;        Groundhog    : TDateTime;&lt;br /&gt;        Halloween    : TDateTime;&lt;br /&gt;        Lincoln      : TDateTime;&lt;br /&gt;        Mothers      : TDateTime;&lt;br /&gt;        StPatty      : TDateTime;&lt;br /&gt;        UnitedNations: TDateTime;&lt;br /&gt;        Valentines   : TDateTime;&lt;br /&gt;        Election     : TDateTime;&lt;br /&gt;        Flag         : TDateTime;&lt;br /&gt;        Easter       : TDateTime;&lt;br /&gt;        &lt;span class="kwrd"&gt;constructor&lt;/span&gt; Create(aYear:word);&lt;br /&gt;        &lt;span class="kwrd"&gt;procedure&lt;/span&gt; changeYear(aYear:word);&lt;br /&gt;        &lt;span class="kwrd"&gt;function&lt;/span&gt; getEaster:TDateTime;&lt;br /&gt;        &lt;span class="kwrd"&gt;class procedure&lt;/span&gt; SafeMonth(var month, y:word);&lt;br /&gt;        &lt;span class="kwrd"&gt;class function&lt;/span&gt; getDOW(year, month, dow, weekNum:word):TDateTime;&lt;br /&gt;        &lt;span class="kwrd"&gt;class function&lt;/span&gt; getLastDOW(year, month, dow:word):TDateTime;&lt;br /&gt;     end;&lt;br /&gt;&lt;br /&gt;implementation&lt;br /&gt;&lt;br /&gt;&lt;span class="kwrd"&gt;class procedure&lt;/span&gt; THolidayClass.SafeMonth(var month, y:&lt;span class="kwrd"&gt;word&lt;/span&gt;);&lt;br /&gt;&lt;span class="kwrd"&gt;begin&lt;/span&gt;&lt;br /&gt;&lt;span class="kwrd"&gt;while&lt;/span&gt; month&amp;gt;12 &lt;span class="kwrd"&gt;do&lt;/span&gt;&lt;br /&gt;   &lt;span class="kwrd"&gt;begin&lt;/span&gt;&lt;br /&gt;   dec(month,12);&lt;br /&gt;   inc(y);&lt;br /&gt;   &lt;span class="kwrd"&gt;end;&lt;/span&gt;&lt;br /&gt;&lt;span class="kwrd"&gt;end;&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span class="kwrd"&gt;class function&lt;/span&gt; THolidayClass.getDOW(year, month, dow, weekNum:&lt;span class="kwrd"&gt;word&lt;/span&gt;):TDateTime;&lt;br /&gt;&lt;span class="kwrd"&gt;var&lt;/span&gt; i:&lt;span class="kwrd"&gt;word&lt;/span&gt;;&lt;br /&gt;&lt;span class="kwrd"&gt;begin&lt;/span&gt;&lt;br /&gt;result:=EncodeDate(year, month, 1);&lt;br /&gt;&lt;span class="kwrd"&gt;for&lt;/span&gt; i:=0 &lt;span class="kwrd"&gt;to&lt;/span&gt; 7 &lt;span class="kwrd"&gt;do&lt;/span&gt;&lt;br /&gt;   &lt;span class="kwrd"&gt;if&lt;/span&gt; DayOfWeek(result+i)=dow &lt;span class="kwrd"&gt;then&lt;/span&gt;&lt;br /&gt;      &lt;span class="kwrd"&gt;begin&lt;/span&gt;&lt;br /&gt;      result:=result+i;&lt;br /&gt;      result:=result+((weeknum-1)*7); &lt;span class="rem"&gt;//move to the correct week, 1st week is inc of 0&lt;/span&gt;&lt;br /&gt;      &lt;span class="kwrd"&gt;break&lt;/span&gt;;&lt;br /&gt;      &lt;span class="kwrd"&gt;end;&lt;/span&gt;&lt;br /&gt;&lt;span class="kwrd"&gt;end;&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span class="kwrd"&gt;class function&lt;/span&gt; THolidayClass.getLastdow(year, month, dow:&lt;span class="kwrd"&gt;word&lt;/span&gt;):TDateTime;&lt;br /&gt;&lt;span class="kwrd"&gt;var&lt;/span&gt; i:&lt;span class="kwrd"&gt;word;&lt;/span&gt;&lt;br /&gt;&lt;span class="kwrd"&gt;begin&lt;/span&gt;&lt;br /&gt;&lt;span class="rem"&gt;//Year has to be on the stack, SafeMonth could change year&lt;/span&gt;&lt;br /&gt;inc(month);&lt;br /&gt;SafeMonth(month,year);&lt;br /&gt;result:=EncodeDate(year,month,1)-1;&lt;br /&gt;&lt;span class="kwrd"&gt;for&lt;/span&gt; i:=0 &lt;span class="kwrd"&gt;to&lt;/span&gt; 7 &lt;span class="kwrd"&gt;do&lt;/span&gt;&lt;br /&gt;   &lt;span class="kwrd"&gt;if&lt;/span&gt; DayOfWeek(result-i)=dow then&lt;br /&gt;      &lt;span class="kwrd"&gt;begin&lt;/span&gt;&lt;br /&gt;      result:=result-i;&lt;br /&gt;      &lt;span class="kwrd"&gt;break&lt;/span&gt;;&lt;br /&gt;      &lt;span class="kwrd"&gt;end;&lt;/span&gt;&lt;br /&gt;&lt;span class="kwrd"&gt;end;&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span class="kwrd"&gt;constructor&lt;/span&gt; THolidayClass.Create(aYear:&lt;span class="kwrd"&gt;word&lt;/span&gt;);&lt;br /&gt;&lt;span class="kwrd"&gt;begin&lt;/span&gt;&lt;br /&gt;ChangeYear(aYear);&lt;br /&gt;&lt;span class="kwrd"&gt;end;&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span class="kwrd"&gt;function&lt;/span&gt; THolidayClass.getEaster:TDateTime;&lt;br /&gt;&lt;span class="kwrd"&gt;var&lt;/span&gt; a,b,c,d,e,f,g,h,i,k,l,m,p  : &lt;span class="kwrd"&gt;integer;&lt;/span&gt;&lt;br /&gt;    Easter_Month, Easter_Day   : &lt;span class="kwrd"&gt;integer;&lt;/span&gt;&lt;br /&gt;&lt;span class="kwrd"&gt;begin&lt;/span&gt;&lt;br /&gt;   a:=yearis mod 19;&lt;br /&gt;   b:=yearis div 100;&lt;br /&gt;   c:=yearis mod 100;&lt;br /&gt;   d:=b div 4;&lt;br /&gt;   e:=b mod 4;&lt;br /&gt;   f:=(b+8) div 25;&lt;br /&gt;   g:=(b-f+1) div 3;&lt;br /&gt;   h:=(19*a+b-d-g+15) mod 30;&lt;br /&gt;   i:=c div 4;&lt;br /&gt;   k:=c mod 4;&lt;br /&gt;   l:=(32+2*e+2*i-h-k) mod 7;&lt;br /&gt;   m:=(a+11*h+22*l) div 451;&lt;br /&gt;   Easter_Month :=(h+l-7*m+114) div 31; //[3=March, 4=April]&lt;br /&gt;   p:=(h+l-7*m+114) mod 31;&lt;br /&gt;   Easter_Day:=p+1; //(day in Easter Month)&lt;br /&gt;   result:=EncodeDate(YearIs,Easter_Month,Easter_Day);&lt;br /&gt;&lt;span class="kwrd"&gt;end;&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;span class="kwrd"&gt;procedure&lt;/span&gt; THolidayClass.ChangeYear(aYear:&lt;span class="kwrd"&gt;word&lt;/span&gt;);&lt;br /&gt;&lt;span class="kwrd"&gt;const&lt;/span&gt;&lt;br /&gt;   DayOfWeek_Sunday    = 1;&lt;br /&gt;   DayOfWeek_Monday    = 2;&lt;br /&gt;   DayOfWeek_Tuesday   = 3;&lt;br /&gt;   DayOfWeek_Wednesday = 4;&lt;br /&gt;   DayOfWeek_Thursday  = 5;&lt;br /&gt;   DayOfWeek_Friday    = 6;&lt;br /&gt;   DayOfWeek_Saturday  = 7;&lt;br /&gt;&lt;br /&gt;&lt;span class="kwrd"&gt;begin&lt;/span&gt;&lt;br /&gt;YearIs       := aYear;&lt;br /&gt;Easter       := getEaster;&lt;br /&gt;NewYears     := EncodeDate(YearIs,1,1);&lt;br /&gt;MLKJr        := getdow(YearIs, 1, DayOfWeek_Monday, 3);&lt;br /&gt;&lt;span class="kwrd"&gt;if&lt;/span&gt; (YearIs - 1937) mod 4 = 0 &lt;span class="kwrd"&gt;then&lt;/span&gt;&lt;br /&gt;   Inauguration := EncodeDate(YearIs, 1, 20)&lt;br /&gt;&lt;span class="kwrd"&gt;else&lt;/span&gt;&lt;br /&gt;   Inauguration := 0;&lt;br /&gt;Election     := 0;&lt;br /&gt;Flag         := EncodeDate(YearIs,6,14);&lt;br /&gt;Washington   := getdow(YearIs, 2, DayOfWeek_Monday, 3);&lt;br /&gt;ArmedForces  := getdow(YearIs, 5, DayOfWeek_Saturday, 3);&lt;br /&gt;Memorial     := getLastdow(YearIs, 5, DayOfWeek_Monday);&lt;br /&gt;FlagDay      := EncodeDate(YearIs,6,14);&lt;br /&gt;Independence := EncodeDate(YearIs,7,4);&lt;br /&gt;Labor        := getdow(YearIs, 9, DayOfWeek_Monday,1);&lt;br /&gt;Columbus     := getdow(YearIs, 10, DayOfWeek_Monday,2);&lt;br /&gt;Veterans     := EncodeDate(YearIs,11,11);&lt;br /&gt;Thanksgiving := getdow(YearIs, 11, DayOfWeek_Thursday,4);&lt;br /&gt;Christmas    := EncodeDate(YearIs,12,25);&lt;br /&gt;Secretaries  := getLastdow(YearIs, 5, DayOfWeek_Saturday) - 3; &lt;span class="rem"&gt;//wednesday before last saturday in april&lt;/span&gt;&lt;br /&gt;AprilFools   := EncodeDate(YearIs,4,1);&lt;br /&gt;&lt;br /&gt;Earth        := EncodeDate(YearIs,4,22);&lt;br /&gt;Fathers      := getdow(YearIs, 6, DayOfWeek_Sunday,3);&lt;br /&gt;Groundhog    := EncodeDate(YearIs,2,2);&lt;br /&gt;Halloween    := EncodeDate(YearIs,10,31);&lt;br /&gt;Lincoln      := EncodeDate(YearIs,2,12);&lt;br /&gt;Mothers      := getdow(YearIs, 5, DayOfWeek_Sunday,2);&lt;br /&gt;StPatty      := EncodeDate(YearIs,3,17);&lt;br /&gt;UnitedNations:= EncodeDate(YearIs,10,24);&lt;br /&gt;Valentines   := EncodeDate(YearIs,2,14);&lt;br /&gt;&lt;span class="kwrd"&gt;end;&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span class="kwrd"&gt;end.&lt;/span&gt;&lt;br /&gt;&lt;/pre&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/6458454884392032777-3620983740808815786?l=ruminatedrumblings.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://ruminatedrumblings.blogspot.com/feeds/3620983740808815786/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=6458454884392032777&amp;postID=3620983740808815786' title='4 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/6458454884392032777/posts/default/3620983740808815786'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/6458454884392032777/posts/default/3620983740808815786'/><link rel='alternate' type='text/html' href='http://ruminatedrumblings.blogspot.com/2008/03/holidays.html' title='Holidays'/><author><name>Marshall Fryman</name><uri>http://www.blogger.com/profile/02996248168525053524</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>4</thr:total></entry><entry><id>tag:blogger.com,1999:blog-6458454884392032777.post-1998810823910050497</id><published>2008-03-28T12:59:00.000-07:00</published><updated>2008-03-28T13:38:13.015-07:00</updated><title type='text'>Delphi Case with Strings</title><content type='html'>Zarko Gajic posted about this topic on his Delphi Tips &lt;a href="http://delphi.about.com/cs/adptips2002/a/bltip0202_5.htm"&gt;recently&lt;/a&gt; showing how one could use a case statement with strings. His solution basically passes in an array on the stack and then iterates through it providing the index number of the matching string. I don't often want to do this, but the idea comes up occassionally enough that I thought I'd play with it a little.&lt;br /&gt;&lt;br /&gt;The first thing that struck me with this is that passing things on the stack is bound to be slow. Any time you can avoid memory allocation in your routines, do it. The way Zarko wrote his StringToCaseSelect routine created a COPY of the information on the stack. In my testing, just changing the CaseList: array of string to CaseList:const array of string improved the performance of the code by almost 30% for his example. Mind, I'm not using hyper-precise counters; however, it definitely makes a difference.&lt;br /&gt;&lt;br /&gt;Secondly, I was curious how the performance changed if I used the old stand-by: If then else. Using the same testing routine (and imprecise timers), If Then Else is 368% percent faster than the original, non-const version and 283% faster than the const version. That's a pretty hefty speed penalty to pay just for using a case with strings.&lt;br /&gt;&lt;br /&gt;&lt;!-- code formatted by http://manoli.net/csharpformat/ --&gt;&lt;br /&gt;&lt;pre class="csharpcode"&gt;&lt;br /&gt;&lt;span class="kwrd"&gt;procedure&lt;/span&gt; TForm1.standardIF;&lt;br /&gt;&lt;span class="kwrd"&gt;const&lt;/span&gt; strAb = &lt;span class="str"&gt;'About'&lt;/span&gt;;&lt;br /&gt;      strBl = &lt;span class="str"&gt;'Borland'&lt;/span&gt;;&lt;br /&gt;      strDl = &lt;span class="str"&gt;'Delphi'&lt;/span&gt;;&lt;br /&gt;&lt;span class="kwrd"&gt;var&lt;/span&gt; s:&lt;span class="kwrd"&gt;string&lt;/span&gt;;&lt;br /&gt;&lt;span class="kwrd"&gt;begin&lt;/span&gt;&lt;br /&gt;     &lt;span class="kwrd"&gt;if&lt;/span&gt; s=strAB &lt;span class="kwrd"&gt;then begin end&lt;/span&gt;&lt;br /&gt;&lt;span class="kwrd"&gt;else&lt;/span&gt; &lt;span class="kwrd"&gt;if&lt;/span&gt; s=strBl &lt;span class="kwrd"&gt;then begin end&lt;/span&gt;&lt;br /&gt;&lt;span class="kwrd"&gt;else&lt;/span&gt; &lt;span class="kwrd"&gt;if&lt;/span&gt; s=strDl &lt;span class="kwrd"&gt;then begin end&lt;/span&gt;&lt;br /&gt;&lt;span class="kwrd"&gt;end;&lt;/span&gt;&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;Finally, I started to wonder if there wasn't a faster way to do this. It is likely the iteration and memory operations that are consuming so much time in his example. Trying to reduce this lead me back to everyone's favorite string solution: the hash. CodeGear has a very simple hash routine they use in inifiles (TStringHash.HashOf). Taking that code, I tried using it as a simple&lt;br /&gt;&lt;!-- code formatted by http://manoli.net/csharpformat/ --&gt;&lt;br /&gt;&lt;pre class="csharpcode"&gt;&lt;br /&gt;&lt;span class="kwrd"&gt;case&lt;/span&gt; HashOf(&lt;span class="str"&gt;'Delphi'&lt;/span&gt;) &lt;span class="kwrd"&gt;of&lt;/span&gt;&lt;br /&gt;HashOf(&lt;span class="str"&gt;'About'&lt;/span&gt;)   : &lt;span class="kwrd"&gt;begin end;&lt;/span&gt;&lt;br /&gt;HashOf(&lt;span class="str"&gt;'Borland'&lt;/span&gt;) : &lt;span class="kwrd"&gt;begin end;&lt;/span&gt;&lt;br /&gt;HashOf(&lt;span class="str"&gt;'Delphi'&lt;/span&gt;)  : &lt;span class="kwrd"&gt;begin end;&lt;/span&gt;&lt;br /&gt;&lt;span class="kwrd"&gt;end;&lt;/span&gt;&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;but forgot that the items must be constants. Since Delphi doesn't have a precompiler, that leaves me with the ugly task of generating the hash values for each string and then using those constants in my case. That provides me with the following code:&lt;br /&gt;&lt;!-- code formatted by http://manoli.net/csharpformat/ --&gt;&lt;br /&gt;&lt;pre class="csharpcode"&gt;&lt;br /&gt;&lt;span class="kwrd"&gt;procedure&lt;/span&gt; TForm1.delphiHash;&lt;br /&gt;&lt;span class="kwrd"&gt;const&lt;/span&gt; cnAb = 24272; &lt;span class="rem"&gt;//HashOf('About');&lt;/span&gt;&lt;br /&gt;      cnBl = 389836; &lt;span class="rem"&gt;//HashOf('Borland');&lt;/span&gt;&lt;br /&gt;      cnDl = 92361; &lt;span class="rem"&gt;//HashOf('Delphi');&lt;/span&gt;&lt;br /&gt;&lt;span class="kwrd"&gt;begin&lt;/span&gt;&lt;br /&gt;&lt;span class="rem"&gt;//from delphi hash inifiles&lt;/span&gt;&lt;br /&gt;&lt;span class="kwrd"&gt;case&lt;/span&gt; HashOf(&lt;span class="str"&gt;'Delphi'&lt;/span&gt;) &lt;span class="kwrd"&gt;of&lt;/span&gt;&lt;br /&gt;cnAb : &lt;span class="kwrd"&gt;begin end;&lt;/span&gt;&lt;br /&gt;cnBl : &lt;span class="kwrd"&gt;begin end;&lt;/span&gt;&lt;br /&gt;cnDl : &lt;span class="kwrd"&gt;begin end;&lt;/span&gt;&lt;br /&gt;&lt;span class="kwrd"&gt;end;&lt;/span&gt;&lt;br /&gt;&lt;span class="kwrd"&gt;end;&lt;/span&gt;&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;That's quite a bit of work just to use a case with a string, but the performance actually does mean it might be worthwhile. In my tests, I found the case hash style ran 204% faster than the if then else, 577% faster than the const version of StringCaseSelect and 750% faster than the original StringCaseSelect.&lt;br /&gt;&lt;br /&gt;Even though all of that is true, I have to admit that the performance difference on a modern CPU wasn't visible until I ran up to the 10,000,000 iterations or more. If you have a rarely-used routine, you could use which ever method suits you. If you have one that gets hammered a lot, the If Then Else style makes the most sense. I cannot really see the point where the payback for doing all the work of the precompiler makes a lot of sense to using the case hash style.&lt;br /&gt;&lt;br /&gt;Of course, in my own development I rarely run into a case string need so perhaps you have a need that does make it worth while. If so, keep in mind that a hash does &lt;span style="font-weight: bold;"&gt;not&lt;/span&gt; guarantee uniqueness. It's unlikely you'll hit a duplicate, but not impossible. The less random the data, the more unlikely duplicates become.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/6458454884392032777-1998810823910050497?l=ruminatedrumblings.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://ruminatedrumblings.blogspot.com/feeds/1998810823910050497/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=6458454884392032777&amp;postID=1998810823910050497' title='10 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/6458454884392032777/posts/default/1998810823910050497'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/6458454884392032777/posts/default/1998810823910050497'/><link rel='alternate' type='text/html' href='http://ruminatedrumblings.blogspot.com/2008/03/delphi-case-with-strings.html' title='Delphi Case with Strings'/><author><name>Marshall Fryman</name><uri>http://www.blogger.com/profile/02996248168525053524</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>10</thr:total></entry><entry><id>tag:blogger.com,1999:blog-6458454884392032777.post-5838899011527485671</id><published>2008-03-27T16:23:00.000-07:00</published><updated>2008-03-27T16:57:17.547-07:00</updated><title type='text'>Another Vista oddity</title><content type='html'>I've assumed, incorrectly apparently, that the Vista "Run as Administrator" function is akin to the sudo or su function in *nix systems. For those not familiar with sudo, it basically provides a one-time elevation of privileges to execute a special command or a command requiring additional user rights. Su basically creates a new security context using the super user and switches into that context (i.e., in a shell, typing su and then the super user password gives you the "super user shell").&lt;br /&gt;&lt;br /&gt;Vista does not appear to hold this idea, or at the very least, not entirely. The thing that started me down this path is my use of the subst command. For those who haven't read some of my other articles, I use subst to create a virtual environment letting me work on multiple projects without having to pull the source code down from svn (i.e., c:\source\code1, c:\source\code2, etc. get swaped out to be j:\ for which ever path I'm working with at the time). At any rate, I had my normal command prompt open, substed in the paths I wanted and fired up Delphi 2007. Everything worked great except D2007 locked up everytime I hit a particular bug. Thinking it might be a privledge error causing Delphi to hang, I started Delphi using "Run As Administrator".&lt;br /&gt;&lt;br /&gt;Suddenly, nothing would compile. I kept getting error messages saying that the files were missing or locked. Thinking I'd somehow gotten a lock on my files, I rebooted, repeated the process and got the same results. I checked the subst in the command prompt and everything was fine. As a double-check, I then opened a command prompt using "Run As Administrator", typed in subst and voila, no substed drives. Subst in the drives and suddenly everything works as expected.&lt;br /&gt;&lt;br /&gt;Apparently, the "Run As Administrator" function has a lot more in common with Terminal Services than it does an elevated privledge in the same session. If you're having problems, you may want to make sure the settings apply equally to the logged in user AND to the "Run As" user.&lt;br /&gt;&lt;br /&gt;EDIT:&lt;br /&gt;&lt;br /&gt;In another discovery, the network doesn't remember connections either. I have no idea why I thought it would, but it definitely doesn't. If you perform a net use z: \\somedrive\someshare in a normal session, it won't show up in your Run As sessions (and vice versa).&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/6458454884392032777-5838899011527485671?l=ruminatedrumblings.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://ruminatedrumblings.blogspot.com/feeds/5838899011527485671/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=6458454884392032777&amp;postID=5838899011527485671' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/6458454884392032777/posts/default/5838899011527485671'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/6458454884392032777/posts/default/5838899011527485671'/><link rel='alternate' type='text/html' href='http://ruminatedrumblings.blogspot.com/2008/03/another-vista-oddity.html' title='Another Vista oddity'/><author><name>Marshall Fryman</name><uri>http://www.blogger.com/profile/02996248168525053524</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-6458454884392032777.post-5365198445577073128</id><published>2008-03-04T12:25:00.000-08:00</published><updated>2008-03-06T09:42:03.750-08:00</updated><title type='text'>Vista UAC Manifest</title><content type='html'>Here's a couple of interesting little tidbits for those using Delphi 2007 and trying to create manifest files to require your program to run as Administrator. For those who don't know what this means, we're talking about running a program and receiving the wonderful little pop-up "A program is trying to take over your life"... well, something like that anyway. You will need your program to receive elevated privileges if you want to do certain things. In my particular instance, I wanted to write to the HKEY_CLASSES_ROOT registry entries. This isn't supposed to be a full reference to what a manifest is, how it works, etc., etc. Microsoft has documented the UAC in some depth and I recommend using their documentation if you want to really understand your options.&lt;br /&gt;&lt;br /&gt;First, the manifest structure is basically just an XML document that tells Vista how it should handle the program. For elevated privileges, it should look like:&lt;br /&gt;&lt;pre class="csharpcode"&gt;&lt;br /&gt;&lt;span class="kwrd"&gt;&amp;lt;&lt;/span&gt;&lt;span class="html"&gt;assembly&lt;/span&gt; &lt;span class="attr"&gt;xmlns&lt;/span&gt;&lt;span class="kwrd"&gt;="urn:schemas-microsoft-com:asm.v1"&lt;/span&gt; &lt;span class="attr"&gt;manifestversion&lt;/span&gt;&lt;span class="kwrd"&gt;="1.0"&lt;/span&gt;&lt;span class="kwrd"&gt;&amp;gt;&lt;/span&gt;&lt;br /&gt;&lt;span class="kwrd"&gt;&amp;lt;&lt;/span&gt;&lt;span class="html"&gt;assemblyidentity&lt;/span&gt; &lt;span class="attr"&gt;version&lt;/span&gt;&lt;span class="kwrd"&gt;="1.0.0.0"&lt;/span&gt; &lt;span class="attr"&gt;processorarchitecture&lt;/span&gt;&lt;span class="kwrd"&gt;="X86"&lt;/span&gt; &lt;span class="attr"&gt;name&lt;/span&gt;&lt;span class="kwrd"&gt;="Vista UAC Compat.Application"&lt;/span&gt; &lt;span class="attr"&gt;type&lt;/span&gt;&lt;span class="kwrd"&gt;="win32"&lt;/span&gt;&lt;span class="kwrd"&gt;&amp;gt;&lt;/span&gt;&lt;br /&gt;&lt;span class="kwrd"&gt;&amp;lt;&lt;/span&gt;&lt;span class="html"&gt;description&lt;/span&gt;&lt;span class="kwrd"&gt;&amp;gt;&lt;/span&gt;WindowsVistaReadiness Application&lt;span class="kwrd"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="html"&gt;description&lt;/span&gt;&lt;span class="kwrd"&gt;&amp;gt;&lt;/span&gt;&lt;br /&gt;&lt;span class="kwrd"&gt;&amp;lt;&lt;/span&gt;&lt;span class="html"&gt;trustinfo&lt;/span&gt; &lt;span class="attr"&gt;xmlns&lt;/span&gt;&lt;span class="kwrd"&gt;="urn:schemas-microsoft-com:asm.v3"&lt;/span&gt;&lt;span class="kwrd"&gt;&amp;gt;&lt;/span&gt;&lt;br /&gt;&lt;span class="kwrd"&gt;&amp;lt;&lt;/span&gt;&lt;span class="html"&gt;security&lt;/span&gt;&lt;span class="kwrd"&gt;&amp;gt;&lt;/span&gt;&lt;br /&gt;&lt;span class="kwrd"&gt;&amp;lt;&lt;/span&gt;&lt;span class="html"&gt;requestedprivileges&lt;/span&gt;&lt;span class="kwrd"&gt;&amp;gt;&lt;/span&gt;&lt;br /&gt;&lt;span class="kwrd"&gt;&amp;lt;&lt;/span&gt;&lt;span class="html"&gt;requestedexecutionlevel&lt;/span&gt; &lt;span class="attr"&gt;level&lt;/span&gt;&lt;span class="kwrd"&gt;="requireAdministrator"&lt;/span&gt;&lt;span class="kwrd"&gt;&amp;gt;&lt;/span&gt;&lt;br /&gt;&lt;span class="kwrd"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="html"&gt;requestedexecutionlevel&lt;/span&gt;&lt;span class="kwrd"&gt;&amp;gt;&lt;/span&gt;&lt;br /&gt;&lt;span class="kwrd"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="html"&gt;requestedprivileges&lt;/span&gt;&lt;span class="kwrd"&gt;&amp;gt;&lt;/span&gt;&lt;br /&gt;&lt;span class="kwrd"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="html"&gt;security&lt;/span&gt;&lt;span class="kwrd"&gt;&amp;gt;&lt;/span&gt;&lt;br /&gt;&lt;span class="kwrd"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="html"&gt;trustinfo&lt;/span&gt;&lt;span class="kwrd"&gt;&amp;gt;&lt;/span&gt;&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;(thanks to Henrik Bruhn who helpfully posted the above manifest on borland.public.delphi.non-technical)&lt;br /&gt;&lt;br /&gt;Second, D2007 automatically includes a manifest file. If you manually create a manifest file, you wind up with two manifests attached to your program. This will actually create a DCC32 error when you go to compile (duplicate resource). In order to fix this, you have to disable run-time themes under Project/Options/Application. Of course, you then become responsible for inserting the appropriate ComCtrl32 language into the manifest to "upgrade" to the themed ComCtrl32 library that became available in Windows XP. Don't ask me why CodeGear didn't give a little check box to enable this feature. It may have something to do with my fifth point below. At any rate, the updated manifest file (merged with what D2007 automatically includes) looks like:&lt;br /&gt;&lt;!-- code formatted by http://manoli.net/csharpformat/ --&gt;&lt;br /&gt;&lt;pre class="csharpcode"&gt;&lt;br /&gt;&lt;span class="kwrd"&gt;&amp;lt;&lt;/span&gt;&lt;span class="html"&gt;assembly&lt;/span&gt; &lt;span class="attr"&gt;xmlns&lt;/span&gt;&lt;span class="kwrd"&gt;="urn:schemas-microsoft-com:asm.v1"&lt;/span&gt; &lt;span class="attr"&gt;manifestversion&lt;/span&gt;&lt;span class="kwrd"&gt;="1.0"&lt;/span&gt;&lt;span class="kwrd"&gt;&amp;gt;&lt;/span&gt;&lt;br /&gt;&lt;span class="kwrd"&gt;&amp;lt;&lt;/span&gt;&lt;span class="html"&gt;assemblyidentity&lt;/span&gt; &lt;span class="attr"&gt;type&lt;/span&gt;&lt;span class="kwrd"&gt;="win32"&lt;/span&gt; &lt;span class="attr"&gt;name&lt;/span&gt;&lt;span class="kwrd"&gt;="CodeGear RAD Studio"&lt;/span&gt; &lt;span class="attr"&gt;version&lt;/span&gt;&lt;span class="kwrd"&gt;="11.0.2804.9245"&lt;/span&gt; &lt;span class="attr"&gt;processorarchitecture&lt;/span&gt;&lt;span class="kwrd"&gt;="*"&lt;/span&gt;&lt;span class="kwrd"&gt;&amp;gt;&lt;/span&gt;&lt;br /&gt;&lt;span class="kwrd"&gt;&amp;lt;&lt;/span&gt;&lt;span class="html"&gt;dependency&lt;/span&gt;&lt;span class="kwrd"&gt;&amp;gt;&lt;/span&gt;&lt;br /&gt;&lt;span class="kwrd"&gt;&amp;lt;&lt;/span&gt;&lt;span class="html"&gt;dependentassembly&lt;/span&gt;&lt;span class="kwrd"&gt;&amp;gt;&lt;/span&gt;&lt;br /&gt;&lt;span class="kwrd"&gt;&amp;lt;&lt;/span&gt;&lt;span class="html"&gt;assemblyidentity&lt;/span&gt; &lt;span class="attr"&gt;type&lt;/span&gt;&lt;span class="kwrd"&gt;="win32"&lt;/span&gt; &lt;span class="attr"&gt;name&lt;/span&gt;&lt;span class="kwrd"&gt;="Microsoft.Windows.Common-Controls"&lt;/span&gt; &lt;span class="attr"&gt;version&lt;/span&gt;&lt;span class="kwrd"&gt;="6.0.0.0"&lt;/span&gt; &lt;span class="attr"&gt;publickeytoken&lt;/span&gt;&lt;span class="kwrd"&gt;="6595b64144ccf1df"&lt;/span&gt; &lt;span class="attr"&gt;language&lt;/span&gt;&lt;span class="kwrd"&gt;="*"&lt;/span&gt; &lt;span class="attr"&gt;processorarchitecture&lt;/span&gt;&lt;span class="kwrd"&gt;="*"&lt;/span&gt;&lt;span class="kwrd"&gt;&amp;gt;&lt;/span&gt;&lt;br /&gt;&lt;span class="kwrd"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="html"&gt;assemblyidentity&lt;/span&gt;&lt;span class="kwrd"&gt;&amp;gt;&lt;/span&gt;&lt;br /&gt;&lt;span class="kwrd"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="html"&gt;dependentassembly&lt;/span&gt;&lt;span class="kwrd"&gt;&amp;gt;&lt;/span&gt;&lt;br /&gt;&lt;span class="kwrd"&gt;&amp;lt;&lt;/span&gt;&lt;span class="html"&gt;trustinfo&lt;/span&gt; &lt;span class="attr"&gt;xmlns&lt;/span&gt;&lt;span class="kwrd"&gt;="urn:schemas-microsoft-com:asm.v3"&lt;/span&gt;&lt;span class="kwrd"&gt;&amp;gt;&lt;/span&gt;&lt;br /&gt;&lt;span class="kwrd"&gt;&amp;lt;&lt;/span&gt;&lt;span class="html"&gt;security&lt;/span&gt;&lt;span class="kwrd"&gt;&amp;gt;&lt;/span&gt;&lt;br /&gt;&lt;span class="kwrd"&gt;&amp;lt;&lt;/span&gt;&lt;span class="html"&gt;requestedprivileges&lt;/span&gt;&lt;span class="kwrd"&gt;&amp;gt;&lt;/span&gt;&lt;br /&gt;&lt;span class="kwrd"&gt;&amp;lt;&lt;/span&gt;&lt;span class="html"&gt;requestedexecutionlevel&lt;/span&gt; &lt;span class="attr"&gt;level&lt;/span&gt;&lt;span class="kwrd"&gt;="requireAdministrator"&lt;/span&gt; &lt;span class="attr"&gt;uiaccess&lt;/span&gt;&lt;span class="kwrd"&gt;="false"&lt;/span&gt;&lt;span class="kwrd"&gt;&amp;gt;&lt;/span&gt;&lt;br /&gt;&lt;span class="kwrd"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="html"&gt;requestedexecutionlevel&lt;/span&gt;&lt;span class="kwrd"&gt;&amp;gt;&lt;/span&gt;&lt;br /&gt;&lt;span class="kwrd"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="html"&gt;requestedprivileges&lt;/span&gt;&lt;span class="kwrd"&gt;&amp;gt;&lt;/span&gt;&lt;br /&gt;&lt;span class="kwrd"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="html"&gt;security&lt;/span&gt;&lt;span class="kwrd"&gt;&amp;gt;&lt;/span&gt;&lt;br /&gt;&lt;span class="kwrd"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="html"&gt;trustinfo&lt;/span&gt;&lt;span class="kwrd"&gt;&amp;gt;&lt;/span&gt;&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;Note that the information in the assemblyIdentity can be changed to match your information instead of just blindly copying D2007's information.&lt;br /&gt;&lt;br /&gt;Third, you have to include the manifest in your dpr. Make sure you've saved the XML from above as some known file name (vista.manifest in my case). To do this, you will need to create an RC and RES files. D2007 makes this fairly straight-forward. You don't even have to fool with brcc32 anymore. Just create a blank text file and insert&lt;br /&gt;&lt;!-- code formatted by http://manoli.net/csharpformat/ --&gt;&lt;br /&gt;&lt;pre class="csharpcode"&gt;&lt;br /&gt;1 24 vista.manifest&lt;br /&gt;&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;in the file. Save that as vistaprog.rc (do &lt;span style="font-weight: bold;"&gt;not&lt;/span&gt; name it the same as either your project or any file in your project, this will cause a resource file conflict.) In your dpr, underneath the&lt;br /&gt;&lt;!-- code formatted by http://manoli.net/csharpformat/ --&gt;&lt;br /&gt;&lt;pre class="csharpcode"&gt;&lt;br /&gt;{$R *.res}&lt;/pre&gt;&lt;br /&gt;add a new line&lt;br /&gt;&lt;!-- code formatted by http://manoli.net/csharpformat/ --&gt;&lt;br /&gt;&lt;pre class="csharpcode"&gt;&lt;br /&gt;{$R &lt;span class="str"&gt;'vistaprog.res'&lt;/span&gt; &lt;span class="str"&gt;'vistaprog.rc'&lt;/span&gt;}&lt;/pre&gt;&lt;br /&gt;Now, when you do your build, D2007 will automatically compile the RC file, include the vista.manifest and generate a RES file which will be linked into the EXE.&lt;br /&gt;&lt;br /&gt;Fourth, you cannot run your program from a substituted (using the subst command) drive. This is probably a minor annoyance for most since subst is used by command line junkies more than anyone else. In my specific case, I have a set of code paths representing versions (i.e., c:\source\v1, c:\source\v2, c:\source\v3) and I use subst to create a working environment that the IDE works with but is totally transparent to which version I'm in. For instance, subst j: c:\source\v? where ? represents the source code version I want to work. This provides a drive letter (j:) that is anchored to that directory. If you do try to run the program from a substed drive, you will see that you get a message "The specified path does not exist. Check the path and try again." If you ran it from the console, you receive the same error message AND a command line message saying "The system cannot find the file xxxx." It works fine if you just move the exe to a normal drive.&lt;br /&gt;&lt;br /&gt;There may be a fifth issue, I haven't quite decided on this one yet. I am currently unable to run an elevated program in D2007. I suspect this is because Vista starts the exe, sees the manifest, terminates the exe and restarts it under the new security level. Obviously, this is not going to make the Delphi debugger very happy. I'm still researching this particular aspect of it. If this is truly what is happening, it should make debugging elevated programs a lot of fun.&lt;br /&gt;&lt;br /&gt;If you are interested in some other articles on the manifest system, look &lt;a href="http://groups.google.com/group/borland.public.delphi.non-technical/browse_thread/thread/7ef557e6f2ba7b08/1546716971efe65d?#1546716971efe65d"&gt;here&lt;/a&gt;, &lt;a href="http://www.drbob42.com/examines/examin88.htm"&gt;the original thread from Henrick on the newsgroup&lt;/a&gt;, &lt;a href="http://www.stevetrefethen.com/blog/ThemingWindowsApplicationsInDelphi2007.aspx"&gt;here for Steve Trefethen talking about the automatic inclusion of manifest info in D2007&lt;/a&gt;, &lt;a href="http://www.swissdelphicenter.ch/torry/showcode.php?id=1118"&gt;here on the XP manifest&lt;/a&gt;, &lt;a href="http://delphi.about.com/library/bluc/text/uc111601a.htm"&gt;here for a discussion on Windows XP manifest and ComCtrl32&lt;/a&gt;, and &lt;a href="http://developersoven.blogspot.com/2007/02/leveraging-vistas-uac-with-delphi-part_27.html"&gt;here for a detailed discussion on UAC&lt;/a&gt;. The last link I provided offers a COM factory mechanism for elevating your program as needed instead of the whole executable all the time. For my particular purposes, I just needed global elevation, but the COM factory is a much more elegant solution if you only occasionally need access.&lt;br /&gt;&lt;br /&gt;Disclaimer: Since I didn't see a step-by-step guide on how to do this anyway, I threw this together as I figured out what was going on. If you have any questions, ask away and I'll try to help.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/6458454884392032777-5365198445577073128?l=ruminatedrumblings.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://ruminatedrumblings.blogspot.com/feeds/5365198445577073128/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=6458454884392032777&amp;postID=5365198445577073128' title='8 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/6458454884392032777/posts/default/5365198445577073128'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/6458454884392032777/posts/default/5365198445577073128'/><link rel='alternate' type='text/html' href='http://ruminatedrumblings.blogspot.com/2008/03/vista-uac-manifest.html' title='Vista UAC Manifest'/><author><name>Marshall Fryman</name><uri>http://www.blogger.com/profile/02996248168525053524</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>8</thr:total></entry><entry><id>tag:blogger.com,1999:blog-6458454884392032777.post-2412169996136615068</id><published>2008-02-22T10:35:00.000-08:00</published><updated>2008-02-22T10:40:36.207-08:00</updated><title type='text'>Introduction</title><content type='html'>This is my first attempt to create a blog of my thoughts on coding and technology. I've been developing software for many years now and have an interest in many of the current (and not so current) languages and technologies. I primarily develop with CodeGear's Delphi and have used its predecessors all the way back to Turbo Pascal 3.0.&lt;br /&gt;&lt;br /&gt;I have specialized in health care technology so some of my posts may be about that industry in specific, while others will discuss various techniques I find either interesting or useful.&lt;br /&gt;&lt;br /&gt;Hopefully, the reader will find the information either relevant or useful. With a touch of luck, perhaps even both.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/6458454884392032777-2412169996136615068?l=ruminatedrumblings.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://ruminatedrumblings.blogspot.com/feeds/2412169996136615068/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=6458454884392032777&amp;postID=2412169996136615068' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/6458454884392032777/posts/default/2412169996136615068'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/6458454884392032777/posts/default/2412169996136615068'/><link rel='alternate' type='text/html' href='http://ruminatedrumblings.blogspot.com/2008/02/introduction.html' title='Introduction'/><author><name>Marshall Fryman</name><uri>http://www.blogger.com/profile/02996248168525053524</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry></feed>
